알고리즘 문제 풀이

[Swift] 프로그래머스 LV2. [3차] 파일명 정렬

lgvv 2022. 4. 16. 15:35

프로그래머스 LV2. [3차] 파일명 정렬

 

 

문제 딱 봤을 때 이건 10분만에 푼다고 생각했는데 결국은 엄청 오래걸렸다.

처음에는 정규 표현식으로 해결하려고 했는데, 정규 표현식 공부를 제대로 해본 적 없어서 구글링으로 사용하는건 학습에 별로 도움 안될거 같아서 패스 (+ 정규 표현식의 시간복잡도에 대한 개념이 없어서 알고리즘이 효율적이지 않을 수도 있단 생각도 들었음)

 

 

오답 코드

 

반례에 대한 질문

https://programmers.co.kr/questions/30185

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

테스트케이스 3, 4, 5, 6, 7, 19, 20번이 틀림

질문 예시도 보는데 보통 3번은 다 맞던데 나만 틀려서 더욱 아쉬웠다.

 

 

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

        // head, number는 무조건 1글자 이상이나 tail은 없을 수도 있다.
        var fileList = [(String, String, String)]()

        // 데이터 정제
        files.forEach { file in

            var numberFlag = false
            var numberRangeStart = -1

            var numberCount = 0 // 숫자는 최대 5개이므로
            for i in 0..<file.count {
                let idx = file.index(file.startIndex, offsetBy: i)

                if file[idx].isNumber && numberCount != 0 && file[idx] == "0" {
                    print(numberCount)
                    numberCount += 1
                }

                if file[idx].isNumber && numberFlag == false {
                    numberFlag = true
                    numberRangeStart = i
                    numberCount = 1
                } else if (!file[idx].isNumber && numberFlag == true) || numberCount >= 5 {
                    // 이때 number의 range가 정해진다.
                    let headIndex = file.index(file.startIndex, offsetBy: numberRangeStart)
                    let head = String(file[..<headIndex])
                    let number = String(file[headIndex..<idx])
                    let tail = String(file[idx...])

                    let data = (head, number, tail)
                    fileList.append(data)
                    numberFlag = false

                    break
                }
            }

            if numberFlag == true { // 여전히 true인 경우는 파일의 tail이 숫자인경우
                let headIndex = file.index(file.startIndex, offsetBy: numberRangeStart)
                let head = String(file[..<headIndex])
                let number = String(file[headIndex...])

                let data = (head, number, "")
                fileList.append(data)
            }
        }

        // 데이터 정렬
        // head -> number -> tail의 우선순위
        let sortedList = fileList.sorted {

            if $0.0.lowercased() == $1.0.lowercased() {
                return Int($0.1)! < Int($1.1)!
            }
            return $0.0 < $1.0
        }

        // 출력부
        var answer = [String]()
        sortedList.forEach { file in
            answer.append("\(file.0)\(file.1)\(file.2)")
        }



        return answer
    }

 

 

정답 코드

카카오 해설도 찾아보고 뭐 진짜 자료를 많이 서칭해봄.

정렬이 stable하지 않은지 찾아보니까 swift 5부터는 정렬이 stable하게 바뀐것 같고 왜 안되는지.

 

아무리 생각해도 로직은 맞는거 같아서 스스로 반례가 될 수 있는 케이스들을 만들어봄.

근데 결국은 정렬 부분의 문제였는데, sortedList쪽에 lowerCased()를 전부 붙여주어야 했다.

 

func solution(_ files:[String]) -> [String] {
        
        // head, number는 무조건 1글자 이상이나 tail은 없을 수도 있다.
        var fileList = [(String, String, String)]()
        
        // 데이터 정제
        files.forEach { file in
            
            var numberFlag = false
            var numberRangeStart = -1
            
            var numberCount = 0 // 숫자는 최대 5개이므로
            for i in 0..<file.count {
                let idx = file.index(file.startIndex, offsetBy: i)
                
                if file[idx].isNumber && numberCount != 0 && file[idx] == "0" {
                    print(numberCount)
                    numberCount += 1
                }
                
                if file[idx].isNumber && numberFlag == false {
                    numberFlag = true
                    numberRangeStart = i
                    numberCount = 1
                } else if (!file[idx].isNumber && numberFlag == true) || numberCount >= 5 {
                    // 이때 number의 range가 정해진다.
                    let headIndex = file.index(file.startIndex, offsetBy: numberRangeStart)
                    let head = String(file[..<headIndex])
                    let number = String(file[headIndex..<idx])
                    let tail = String(file[idx...])
                    
                    let data = (head, number, tail)
                    fileList.append(data)
                    numberFlag = false
                    
                    break
                }
            }
            
            if numberFlag == true { // 여전히 true인 경우는 파일의 tail이 숫자인경우
                let headIndex = file.index(file.startIndex, offsetBy: numberRangeStart)
                let head = String(file[..<headIndex])
                let number = String(file[headIndex...])
                
                let data = (head, number, "")
                fileList.append(data)
            }
        }
        
        // 데이터 정렬
        // head -> number -> tail의 우선순위
        let sortedList = fileList.sorted {

            if $0.0.lowercased() == $1.0.lowercased() {
                return Int($0.1)! < Int($1.1)!
            }
            return $0.0.lowercased() < $1.0.lowercased() // 여기가 문제였음 !! 
        }

        // 출력부
        var answer = [String]()
        sortedList.forEach { file in
            answer.append("\(file.0)\(file.1)\(file.2)")
        }
        
        return answer
    }