[프로그래머스] Lv2. 문자열 압축

zzzzsb·2022년 1월 20일
0

프로그래머스

목록 보기
2/33

문제

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

문제 설명

데이터 처리 전문가가 되고 싶은 "어피치"는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자열에서 같은 값이 연속해서 나타나는 것을 그 문자의 개수와 반복되는 값으로 표현하여 더 짧은 문자열로 줄여서 표현하는 알고리즘을 공부하고 있습니다.

간단한 예로 "aabbaccc"의 경우 "2a2ba3c"(문자가 반복되지 않아 한번만 나타난 경우 1은 생략함)와 같이 표현할 수 있는데, 이러한 방식은 반복되는 문자가 적은 경우 압축률이 낮다는 단점이 있습니다. 예를 들면, "abcabcdede"와 같은 문자열은 전혀 압축되지 않습니다. "어피치"는 이러한 단점을 해결하기 위해 문자열을 1개 이상의 단위로 잘라서 압축하여 더 짧은 문자열로 표현할 수 있는지 방법을 찾아보려고 합니다.

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

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

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

입출력 예

sresult
"aabbaccc"7
"ababcdcdababcdcd"9
"abcabcdede"8
"abcabcabcabcdededededede"14
"xababcdcdababcdcd"17

입출력 예 설명

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

입출력 예 #2
문자열을 8개 단위로 잘라 압축했을 때 가장 짧습니다.

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

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

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


Approach #1

/*
aabbaccc 
1개단위로 잘라 압축-> 2a2ba3c

ababcdcdababcdcd
2개단위로 잘라 압축 ->2ab2cd2ab2cd
8개단위로 잘라 압축 -> 2ababcdcd

abcabcdede
2개단위로 잘라 압축 -> abcabc2de
3개단위로 잘라 압축 -> 2abcdede

ex. aabbacc
1 -> 2a2ba2c(7)
2 -> aabbacc(7)
3 -> aabba2c(7)
4 -> aabbacc(7)
5,6,7 -> (7)

ababcdcdababcdcd
1 -> (16)
2 -> 2ab2cd2ab2cd (12)
3 -> ababcdcdababcdcd (16)
4 -> ababcdcdababcdcd (16)
8 -> 2ababcdcd (9) //min

   0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   a b a b c d c d a b  a  b  c  d  c  d
     ^
         ^

minComStrLen=s.length;
for(let i=1; i<=s.length; i++){
    let compStr = compressStr(s,i);
    minCompStrLen=Math.min(compStr.length, minCompStr.length);
}

compressStr(str,cutLen)함수

for문: 
p1=i;
p2=p1+curLen;
charCnt = 1;
curChar = s[p1] //a

while문 돌면서 s[p2] 체크.
nextChar = s.substr(p2,cutLen); //b

nexChar가 curChar랑 같으면 charCnt++; p2++;
                      
다르면 charCnt>1 이면 "charCnt"+curChar push.
charCnt=1 이면 curChar push. //a
             
*/

compressStr(str,cutLen) 함수는..
cutLen단위로 str을 잘라 압축해주는 함수이다.

solution 함수에서는..
for문을 1부터 s.length-1 까지 돌며 compressStr 함수를 실행시킨다. 반환값으로는 압축된 문자열 CompStr이 나올것이다.
CompStr의 길이와 minComStrLen을 비교하여 더 작은값을 계속 갱신해준다.
for문 종료후 minCompStrLen을 리턴해준다.

Solution #1

function solution(s) {
    let minCompStrLen=s.length;
    
    for(let i=1; i<s.length; i++){
        let compStr = compressStr(s,i);
        minCompStrLen=Math.min(compStr.length, minCompStrLen);
    }
    return minCompStrLen;
}

function compressStr(str, cutLen){
    let p1 = 0;
    let p2 = p1 + cutLen;
    let compStr = "";   
    while(p1<str.length) {
        let charCnt = 1;
        let curChar = str.slice(p1, p1+cutLen); 
        let nextChar = str.slice(p2, p2+cutLen); 
        while(curChar === nextChar){
            charCnt++; 
            p2+=cutLen;
            nextChar = str.slice(p2, p2+cutLen);
        }
        
        if(charCnt>1){
            compStr+=charCnt.toString();
            compStr+=curChar;
        }
        else {
            compStr+=curChar;
        }
        p1 = p2;
        p2 = p1 + cutLen;
    }
    return compStr;
}

N: s.length

Time Complexity

O(N^3)

Space Complexity

O(N)


Review

  1. 프로그래머스에서 처음 풀어보는 레벨2 문제. 45분 재고 풀었으나 1시간 정도 걸렸다. ㅠㅠ
  2. 마찬가지로 문제 이해 + 테스트 케이스 이해 하는데 시간이 꽤 걸렸다. 거의 15-20분 정도? 이런 시간도 줄여야 할것 같음.
  3. 코드 작성하면서 cutLen을 자꾸 curLen으로 쓰는등 오타때문에 수정하는 과정에서 시간이 길어졌다. 변수 이름 설정이나, 평소에 오타 안내도록 신경 잘 써야겠다.
  4. 문자열 관련 함수 진짜 마스터 해야겠다. 오늘은 substr.. ㅎㅎㅎㅎ
  5. 시간복잡도 무려 N^3...!! 이게 최선이었나... 깔끔하고 옵티멀한 코드는 아닌것 같아 마찬가지로 리팩토링이 필요할거 같다.

TIL

  1. str.substr(startIndex, cutLength);
    start 인덱스 기준으로 cutLength 길이만큼 문자를 잘라서 반환해준다.
profile
성장하는 developer

0개의 댓글