본문 바로가기
알고리즘 문제 풀이/프로그래머스

프로그래머스 문자열 압축 Kotlin (문자열)

by 옹구스투스 2021. 9. 7.
반응형

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

 

코딩테스트 연습 - 문자열 압축

데이터 처리 전문가가 되고 싶은 "어피치"는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문

programmers.co.kr

문제 설명

데이터 처리 전문가가 되고 싶은 "어피치"는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자열에서 같은 값이 연속해서 나타나는 것을 그 문자의 개수와 반복되는 값으로 표현하여 더 짧은 문자열로 줄여서 표현하는 알고리즘을 공부하고 있습니다.
간단한 예로 "aabbaccc"의 경우 "2a2ba3c"(문자가 반복되지 않아 한번만 나타난 경우 1은 생략함)와 같이 표현할 수 있는데, 이러한 방식은 반복되는 문자가 적은 경우 압축률이 낮다는 단점이 있습니다. 예를 들면, "abcabcdede"와 같은 문자열은 전혀 압축되지 않습니다. "어피치"는 이러한 단점을 해결하기 위해 문자열을 1개 이상의 단위로 잘라서 압축하여 더 짧은 문자열로 표현할 수 있는지 방법을 찾아보려고 합니다.

예를 들어, "ababcdcdababcdcd"의 경우 문자를 1개 단위로 자르면 전혀 압축되지 않지만, 2개 단위로 잘라서 압축한다면 "2ab2cd2ab2cd"로 표현할 수 있습니다. 다른 방법으로 8개 단위로 잘라서 압축한다면 "2ababcdcd"로 표현할 수 있으며, 이때가 가장 짧게 압축하여 표현할 수 있는 방법입니다.

다른 예로, "abcabcdede"와 같은 경우, 문자를 2개 단위로 잘라서 압축하면 "abcabc2de"가 되지만, 3개 단위로 자른다면 "2abcdede"가 되어 3개 단위가 가장 짧은 압축 방법이 됩니다. 이때 3개 단위로 자르고 마지막에 남는 문자열은 그대로 붙여주면 됩니다.

압축할 문자열 s가 매개변수로 주어질 때, 위에 설명한 방법으로 1개 이상 단위로 문자열을 잘라 압축하여 표현한 문자열 중 가장 짧은 것의 길이를 return 하도록 solution 함수를 완성해주세요.

제한사항

  • s의 길이는 1 이상 1,000 이하입니다.
  • s는 알파벳 소문자로만 이루어져 있습니다.

입출력 예

입출력 예에 대한 설명

입출력 예 #1

문자열을 1개 단위로 잘라 압축했을 때 가장 짧습니다.

입출력 예 #2

문자열을 8개 단위로 잘라 압축했을 때 가장 짧습니다.

입출력 예 #3

문자열을 3개 단위로 잘라 압축했을 때 가장 짧습니다.

입출력 예 #4

문자열을 2개 단위로 자르면 "abcabcabcabc6de" 가 됩니다.
문자열을 3개 단위로 자르면 "4abcdededededede" 가 됩니다.
문자열을 4개 단위로 자르면 "abcabcabcabc3dede" 가 됩니다.
문자열을 6개 단위로 자를 경우 "2abcabc2dedede"가 되며, 이때의 길이가 14로 가장 짧습니다.

입출력 예 #5

문자열은 제일 앞부터 정해진 길이만큼 잘라야 합니다.
따라서 주어진 문자열을 x / ababcdcd / ababcdcd 로 자르는 것은 불가능 합니다.
이 경우 어떻게 문자열을 잘라도 압축되지 않으므로 가장 짧은 길이는 17이 됩니다.

풀이

어렵진 않지만 성가신 문자열 문제이다.

제일 앞부터 정해진 길이만큼 잘라야 한다는 조건이 있으므로, 맨 앞부터, 1개 단위로, 2개 단위로, 3개 단위 등등으로
잘라서 압축하면 된다. 본인은 굳이 압축한 문자열을 만들지는 않고 정답을 구하는 데 필요한 길이만 구했다.

 

문자열의 길이가 length라 할 때, 1개 단위부터, length/2개 단위까지 압축할 수 있다.

i개 단위로 압축할 때,

앞의 단어와 뒤의 단어가 같다면 같다는 flag를 세우고 뒤의 단어를 계속 검색해 나간다.

앞의 단어와 뒤의 단어가 다르다면 다시 flag를 초기화하고, 앞의 단어를 갱신하고, 길이에 i만큼 더해줬다.

i개 단위로 압축할 때, s가 나누어떨어지지 않는다면, 남은 index만큼 길이에 더해줬고, 마지막 단어까지 탐색이 끝났을 때, 앞의 단어와 뒤의 단어가 같다는 flag가 세워진 채로 종료되었다면, 연속으로 문자가 같은 경우의 수인 flag를 더해준다. flag를 더해준다는 것은 앞에 연속으로 문자가 같은 경우, 그 숫자만큼 더하는 것인데, 이 숫자는 한 자리, 두 자리, 세 자릿수 등등이 될 수 있으므로, flag는 Boolean 자료형이 아닌 Int로 연속으로 문자가 같은 경우의 개수를 저장하여,

flag의 자리수만큼 길이에 더해준다.

 

 

코드

import kotlin.math.*
class Solution {
    fun solution(s: String): Int {
        var answer = s.length
        if(s.length==1) return answer
        for(i in 1 .. s.length/2){
            var str = s.substring(0,i)
            var len =i
            var isSame = 1
            var rest = 0
            for(j in i .. s.length-i step i){
                rest = s.length-j-i
                if(str == s.substring(j,j+i)){
                    isSame++
                }
                else{
                    if(isSame>1){
                        len+=isSame.toString().length
                    }
                    isSame=1
                    len+=i
                    str = s.substring(j,j+i)
                }
            }
            if(isSame>1){
                len+=isSame.toString().length
            }
            answer=min(answer,len+rest)
        }
        return answer
    }
}
반응형

댓글