본문 바로가기
알고리즘 문제풀이

[프로그래머스] 파일 정렬 (Swift)

by SiO2whocode 2025. 2. 21.

https://school.programmers.co.kr/learn/courses/30/lessons/17686

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

문자열

파일명이 담긴 배열이 주어지고, 이를 일정한 규칙에 따라 정렬하면 되는데, 규칙은 아래와 같다.

["img12.png", "img10.png", "img2.png", "img1.png"]

우선 이런 파일명들이 주어졌을 때, 파일명을 세 파트로 나눈다. 

HEAD : 파일명의 앞부분에서 숫자가 아닌 부분. 즉 img-12sd.png라면 img- 까지가 HEAD이다. 숫자가 나타난 이후에 나타나는 문자는 포함하지 않음 (영문 알파벳(대소문자)과 특수기호 포함)

NUMBER : HEAD다음에 등장하는 연속되는 숫자 부분. img-12sd.png라면 12가 NUMBER이다. 만약 012여도 12로 취급한다.

TAIL : NUMBER 다음부터 파일명 끝까지의 부분. 딱히 이 문제에서는 신경쓰지 않아도 되는 부분이다.

이렇게 파일명을 세 파트로 나누고 나서 파일명들끼리 정렬을 하려면 비교를 해야하는데 여기에 규칙 몇가지가 있다.

규칙1. 우선, HEAD 부분 비교, 두 파일명 중 HEAD 부분을 알파벳순으로 비교하여 큰 문자열이 뒤로간다. 이때 대소문자는 가리지 않음

규칙2. HEAD 부분이 일치하다면 NUMBER를 비교하는데, 이때 012, 10라면 012가 큰 것이다. 즉 문자열이 아니라 숫자로 비교한다.

규칙3. HEAD와 NUMBER 모두 일치하면 입력된 순서대로 정렬한다.

 

접근방법

커스텀 정렬을 사용하면 편하다. swift에서는 커스텀정렬을 구현하기가 매우 간편하기 때문에 sorted 혹은 sort에 매개변수로 by에 클로저로 함수를 전달해주면 되는데,

그 내부에서 두 파일명(문자열)의 HEAD와 NUMBER를 각각 추출하고 HEAD가 같은경우와 HEAD가 같지 않은 경우, NUMBER가 같은 경우와 NUMBE가 같지 않은 경우, 위의 규칙대로 비교하여 Bool 타입을 리턴하고 모두 같은 경우 인덱스 순서대로 비교한 결과를 리턴하면 된다. (자세한건 소스코드 참고..!!)

 

오답노트

마지막에 모두 같은 경우 당연히 by에 A,B 문자열이 들어올 때 순서대로 들어올 줄 알고 true를 리턴하는걸로 했는데 (그 순서를 유지하도록) 반대로 돼서 false로 바꿨더니 통과가 됐었다. 근데 이해가 안가서 찾아보니까 운..이었던 것 같고, 다른 분들 코드 보니까 인덱스로 비교해서 내보냈길래 그렇게 고쳤다.

A,B가 어떤순서로 들어오는지 살펴보니까 [A,B,C,D] 면, (B,A) -> (C,A) -> (D,B) 이런식으로 들어왔던 것 같다. 애플 공식 문서에 소팅 알고리즘이 nlogn 시간복잡도라는걸 보면 퀵정렬이지 않을까 싶은데 지금 찾아보니 퀵소트와 힙소트를 합친 introsort라고 합니다..

암튼 그러면 순서대로 들어오지는 않는게 맞다는..생각

그래서! 결론은 인덱스 비교해서 반환해줘야한다!

 

소스코드

func getHeadandNum(_ A:String) -> (String, Int) {
    let n = A.count
    let arr = Array(A)
    var head = ""
    var num = ""
    var int = 0
    var i = 0
    while i < n && !arr[i].isNumber {
        head.append(arr[i])
        i += 1
    }
    while i < n && arr[i].isNumber {
        num.append(arr[i])
        i += 1
    }
    int = Int(num)!
    
    return (head.lowercased(), int)
} 

func solution(_ files:[String]) -> [String] {
    
    return files.enumerated().sorted(by: { A, B in
                    var (A_head, A_int) = getHeadandNum(A.element)
                    var (B_head, B_int) = getHeadandNum(B.element)
                    if A_head != B_head {
                        return A_head < B_head
                    } else {
                        if A_int != B_int {
                            return A_int < B_int
                        } else {
                            return A.offset < B.offset
                        }
                    }
                            }).map{$0.element}
}

 

728x90