ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Programmers) Lv2 [2020카카오공채] 문자열 압축
    Algorithm/Programmers 2020. 3. 16. 15:24
    728x90

    출처: https://programmers.co.kr/learn/courses/30/lessons/60057

    분류: Lv2 문자열


    접근방식

    문자열의 길이 N의 절반 이상으로 자르면 압축할 수가 없습니다.
    주의 할 개념은 이정도 나머지는 구현이 핵심입니다.

     

    카카오 테스트 해설의 출제의도는 다음과 같습니다.

    문자열을 다룰 수 있고, 아래 예시와 같이 문자열과 관련된 다양한 작업을 할 수 있는지 파악

    • 문자열 자르기
    • 부분 문자열 얻기
    • 문자열 비교하기
    • 문자열 길이 얻기

     

    Swift 는 문자열 다루기가 상대적으로 까다로운데 자유자재로 사용하려면 역시 많은 연습이 필요하겠습니다 😥

     

    해결방법

    1 ~ N/2 까지 잘라가며 압축 문자열의 길이가 가장 작은 값을 찾아냅니다.

    앞에서부터 압축 문자열의 길이로 잘라내면서 중복을 카운트합니다.
    카운트가 1이면 중복을 카운트 없이 부분 문자열을 result 에 추가시키고
    1 보다 크면 카운트를 앞에 붙여줍니다.

    일일이 분기처리를 하기 싫어서 처음에 카운트가 "1" 이여도 일단 다 붙이고
    이후에 1을 제거하는 방식도 생각했었는데
    이렇게 하면 1000 과 같이 10 이상의 수의 1도 잘라버릴 수가 있습니다 😇

    func solution(_ s:String) -> Int {
    
        var resultCount = s.count
    
        if s.count == 1 { return 1 }
    
        for idx in 1...s.count/2 {
    
            var result = ""
            var indiceStr = ""
            var cnt = 1
            var str = s
    
            while str.count >= idx {
    
                let range = str.startIndex..<str.index(str.startIndex, offsetBy: idx)
    
                if indiceStr == str[range] {
                    cnt += 1
                } else {
                    if cnt == 1 {
                        result += "\(indiceStr)"
                    } else {
                        result += "\(cnt)\(indiceStr)"
                    }
                    indiceStr = String(str[range])
                    cnt = 1
                }
                str.removeFirst(idx)
            }
            if cnt == 1 {
                result += "\(indiceStr)\(str)"
            } else {
                result += "\(cnt)\(indiceStr)\(str)"
            }
    
            if resultCount > result.count { resultCount = result.count }
        }
    
    
        return resultCount
    }

     

    개선된 코드 

    swift에는 기본적으로 문자열을 특정 길이로 자르는 함수는 제공하지 않습니다.
    이 부분을 구현하는 부분 때문에 코드가 복잡해질 수 있는데,
    문자열을 자르는 부분을 extension으로 처리해주면 보다 깔끔하게 처리할 수 있습니다. 

    extension String {
        func split(by length: Int) -> [String] {
            var resultString = [String]()
            
            var string = self
            
            while string.count >= length {
                let range = string.startIndex..<string.index(string.startIndex, offsetBy: length)
                resultString.append(String(string[range]))
                string.removeFirst(length)
            }
            if !string.isEmpty { resultString.append(string) }
            
            return resultString
        }
    }
    
    func solution(_ s:String) -> Int {
    
        if s.count == 1 { return 1 }
        
        var resultCount = s.count
    
        for idx in 1...s.count/2 {
            
            let truncatedString = s.split(by: idx)
    
            var duplicatedStr = ""
            var dupCnt = 1
            var result = ""
            
            for str in truncatedString {
                if str == duplicatedStr {
                    dupCnt += 1
                } else {
                    
                    if dupCnt == 1 {
                        result += duplicatedStr
                    } else {
                        result += "\(dupCnt)\(duplicatedStr)"
                    }
                    duplicatedStr = str
                    dupCnt = 1
                }
                //print(str, duplicatedStr, dupCnt, result)
            }
            
            if dupCnt > 1 {
                result += "\(dupCnt)\(duplicatedStr)"
            } else {
                result += "\(duplicatedStr)"
            }
            //print(truncatedString, idx, result)
            if resultCount > result.count { resultCount = result.count}
        }
        
        return resultCount

     

    여전히 1을 분기처리 하는 부분이 두 번이나 사용되서
    깔끔해 보이지 않아 맘에들지 않네요.. 더 좋은 방법이 있을까요 ㅠ-ㅠ

     

    배운점

    간단한 문제인데 꽤나 오랜 시간이 걸렸다.
    문자열은 거의 빼놓지 않고 한 문제씩은 꼭 나오는 데 확실히 연습해서 시간을 단축하자.

    역시 코드는 네이밍이 정말 중요하다..
    문자열을 다룰 때는 subString이 많이 사용되기 때문에 str, s, 이런 식으로 사용하면
    내 코드에 내가 빠져 허우적 허우적....
    너무 줄이지 말고 깔끔하고 명확한 네이밍을 하자.
    이름을 줄이지 말고 코드를 줄이자 😭😭

    extension을 적극적으로 활용하면 더 가독성 높고 깔끔한 코드를 완성시킬 수가 있다.

     

    댓글

Designed by Tistory.