[Algorithm] 프로그래머스 파일명 정렬

Updated:

문제 설명

3132

나의 풀이

import Foundation
func solution(_ files:[String]) -> [String] {
    var fileList = [File]()
    var numberIndex = [Int]()
    var charIndex = [Int]()
    for file in files {
        for (index, char) in file.enumerated() {
            if char.isNumber {
                numberIndex.append(index)
            }
            else {
                charIndex.append(index)
            }
        }

        let substringIndex1 = file.index(file.startIndex, offsetBy: numberIndex.first!)
        if let a = findFirstIndexCompare(charIndex, numberIndex) {

            let substringIndex2 = file.index(file.startIndex, offsetBy: a)
            let checkIndex2 = file.index(file.startIndex, offsetBy: numberIndex.first! + 5)
            // 숫자가 5개 이상인 경우에는 5개까지만 number로 저장
            if substringIndex2 > checkIndex2 {
                fileList.append(File(head: String(file[file.startIndex..<substringIndex1]),
                                     number: String(file[substringIndex1..<checkIndex2]),
                                     tail: String(file[checkIndex2..<file.endIndex])))
            }
            else {
                fileList.append(File(head: String(file[file.startIndex..<substringIndex1]),
                                     number: String(file[substringIndex1..<substringIndex2]),
                                     tail: String(file[substringIndex2..<file.endIndex])))
            }
        }
        // "F-15"와 같이 tail이 없는 경우
        else {
            fileList.append(File(head: String(file[file.startIndex..<substringIndex1]),
                                 number: String(file[substringIndex1..<file.endIndex]),
                                 tail: nil))
        }
        numberIndex = []
        charIndex = []
    }
    
    let sortedFileList = fileList.sorted { f1, f2 in
        if f1.head.lowercased() < f2.head.lowercased() {
            return true
        }
        else if f1.head.lowercased() == f2.head.lowercased() {
            if Int(f1.number)! < Int(f2.number)! {
                return true
            }
        }
        return false
    }

    return sortedFileList.map {
        if let tail = $0.tail {
            return "\($0.head)\($0.number)\(tail)"
        }
        return "\($0.head)\($0.number)"
    }
}

struct File {
    var head: String
    var number: String
    var tail: String?
}

func findFirstIndexCompare(_ cIndex: [Int], _ nIndex: [Int]) -> Int? {
    for c in cIndex {
        for n in nIndex{
            if c > n {
                return c
            }
        }
    }
    return nil
}

처음에 작성했던 코드는 "F15“와 같은 파일명을 고려하지 않고 무조건 tail이 존재한다고 가정해서 substring을 진행하여 오류가 났었다. 따라서 이를 해결하기 위해서 optional을 사용해서 문제를 해결하였다.

그러나 이 문제에서 ["img12123001.png", "img12123000.png"] 다음과 같은 예시에서 5글자 까지만 숫자로 인정하므로 실제로 정답은 ["img12123001.png", "img12123000.png"] 이 나와야하지만 그렇지 않고 ["img12123000.png", img12123001.png] 이렇게 나오는 것들이 정답으로 인정되고 있다.. 테스트케이스가 추가되어야할 것 같다.

괜찮은 남의 풀이

import Foundation
extension String{
    var numeric: ClosedRange<Character> { return "0"..."9" }
    var head: String{
        return self.prefix { numeric.contains($0) == false }.uppercased()
    }
    var number: Int {
        return Int( self.drop   { numeric.contains($0) == false}
                        .prefix { numeric.contains($0) == true })!
    }
}

func solution(_ files:[String]) -> [String] {

    return files.enumerated().sorted { (lhs, rhs) in
        let l = lhs.element
        let r = rhs.element
        if l.head != r.head { return l.head < r.head}
        if l.number != r.number { return l.number < r.number}
        return lhs.offset < rhs.offset

    }.map{ $0.element }
}

좋은 풀이지만 위에서 언급했던 숫자가 5개 이상인 경우에는 잘못된 정답이 출력된다. 그러나 위에서 조건에 따라서 head, number, tail을 추출하는 방법이 매우 흥미롭다.

참고

Programmers

Leave a comment