알고리즘 문제 풀이

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

lgvv 2022. 4. 16. 15:35

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

 

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

하하,, 문제 딱 봤을 때 이건 10분컷! 이랬는데 결국은 엄청 오래걸림

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

그래서 그냥 for문을 통해서 접근함. 근데!! 65점에서 막혔음 ^__^

 

 

 ✅ 코드 (틀린코드 65점)

 

하도 많이 틀려서 질문도 함.. 반례를 못찾아서 

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
    }