본문 바로가기
알고리즘

[알고리즘] 프로그래머스 문자열 압축(Level 2/2020 카카오 블라인드 채용 문제) [자바/JAVA] 풀이- 개발하는 지토

by 개발하는 지토 2020. 8. 31.

https://programmers.co.kr/learn/courses/30/lessons/60057?language=java

 

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

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

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는 알파벳 소문자로만 이루어져 있습니다.

입출력 예

s result
"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이 됩니다.

 

풀이 코드 [자바/java]

class Solution {
    public int solution(String s) {
        int answer = s.length();
        for(int i=1; i<s.length()/2+1; i++) {
            answer = Math.min(answer, Comp(s, i));
        }
        return answer;
    }

    public static int Comp(String s, int slice) {
        String slice_letter = s.substring(0, slice);
        StringBuilder sb = new StringBuilder();
        sb.append(slice_letter);
        int cnt = 1;
        for(int i=slice; i<s.length(); i +=slice) {
            if(i+slice <= s.length()) {
                if(slice_letter.equals(s.substring(i, i+slice))) {
                    cnt += 1;
                }else {
                    slice_letter = s.substring(i, i+slice);
                    if(cnt > 1) sb.append(cnt);
                    sb.append(slice_letter);
                    cnt = 1;
                }
            } else {
                if(cnt > 1) sb.append(cnt);
                sb.append(s.substring(i));
                cnt = 1;
            }
        }
        if(cnt > 1) sb.append(cnt);
        return sb.toString().length();
    }
}

 

 

내 문제풀이 방법 설명

 

나의 경우에는 직접 문자를 만들어보고 해당 문자의 길이를 return 하여 최솟값을 가지는 경우를 최종 return 하는 풀이를 선택했다.

하지만 실제 해당 문제에서 요구하는 방식으로의 압축이 아닌 알파벳이 먼저 나오고 숫자가 뒤에 나오는 방식으로 진행했다.

이유는 이 방식으로 해야 StringBuilder를 사용해서 문자열을 만들기 편하다고 판단했고 어차피 문제에서 요구하는 것은 문자열의 길이이기 때문에 숫자와 알파벳의 순서는 상관이 없다고 생각했기 때문이다.

 

solution 메서드와 Comp 메서드를 구분했는데, solution 메서드에서 for문을 돌면서 Comp메서드를 호출하는 방식으로 진행했다.

Comp 메서드는 인자로 문자열과 slice 할 정수 값을 받는다.

slice값만큼 기준이 되는 문자열은 slice_letter에 저장하고 StringBuilder에 append 한다.

for문을 돌면서 slice(기준값)만큼 순차적으로 비교하면서 같은 값이라면 cnt를 1 증가시키고 다른 값이라면 StringBuilder에 append 해준다.

이때 cnt가 1보다 크다면 앞에 비교하던 문자가 연속된 문자이기 때문에 먼저 StringBuilder에 append 해준다.

그리고 남는 문자열과 cnt는 앞선 조건과 마찬가지로 StringBuilder에 append 한다.

마지막의 문자열 cnt를 StringBuilder에 최종적으로 append 하고 해당 문자열의 길이를 return 하면서 Comp 메서드가 끝난다.

이후 가장 작은 수의 문자열 길이 값을 answer 변수에 저장하고 마친다.


문제를 다 푼 이후에 다른 분들의 코드를 본 결과 메모리나 시간효율도 측면에서 내 방식처럼 문자열을 직접 만들지 않고 숫자만 세어 return 하는 방식도 좋다고 판단이 되었다. 문제에서 요구하는 답이 무엇이고 어떻게 그 답을 구해낼 것인가에 대한 고민을 한번 더 할 수 있게 된 문제였다.

댓글