https://school.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 함수를 완성해주세요.
제한사항
- s의 길이는 1 이상 1,000 이하입니다.
- s는 알파벳 소문자로만 이루어져 있습니다.
정답 설명
이번 문제를 보자 마자, 몇개 단위로 자르는 게 가장 유리한지 미리 알 수 있는 방법이 있는지 고민했습니다. 당장 떠오르는 방법이 없었기 때문에 바로 모든 경우의 수를 확인하는 완전탐색으로 문제를 해결하였습니다.
압축하는 과정은 다음의 두 단계로 구분지을 수 있습니다.
- 문자열 s를 n의 길이의 단어들로 자른다.
- 압축할 수 있는 부분을 모두 압축 시킨다.
그리고, 압축의 과정은 다음의 방법으로 진행할 수 있습니다.
앞의 단어들과 압축되지 않은 n번째 단어에 대해
- n번째 이후의 단어들을 확인하며 n번째 단어와 같은 단어의 개수를 세아린다.
- n번째 단어와 다른 단어가 등장하면 다음과 같이 처리한다.
- n번째 단어와 같은 단어가 1개 이상이라면 압축을 수행한다.
- n번째 단어와 같은 단어가 없다면 그대로 n번째 단어만 이미 압축이 완료된 문자열에 이어 붙인다.
소스 코드
import java.util.*;
class Solution {
public int solution(String s) {
int cutLen = 1;
int minLen = s.length();
while(cutLen <= s.length() / 2){
ArrayList<String> boca = new ArrayList<>();
int i = 0;
while(i+cutLen < s.length()){
boca.add(s.substring(i, i+cutLen));
i += cutLen;
}
boca.add(s.substring(i));
int start = 0;
int check = 0;
int sameNum = 0;
String result = "";
while(check < boca.size()){
if(check+1 < boca.size() && boca.get(start).equals(boca.get(check + 1))){
check++;
sameNum++;
}
else{
if(sameNum != 0){
result += Integer.toString(sameNum + 1);
}
result += boca.get(start);
start = check+1;
check = start;
sameNum = 0;
}
}
if(result.length() < minLen)
minLen = result.length();
cutLen ++;
}
return minLen;
}
}
회고
문제를 해결한 이후 다른 사람들의 풀이를 보니 더 좋은 방법이 존재했다.
결국 문제에서 필요한 것은 압축이 완료된 이후의 문자열의 길이 이다. 때문에 굳이 압축 결과 문자열을 만들지 않고, 압축 과정에서 결과 문자열에 대한 누적 길이만 계산을 해 주는 식으로 시간을 더욱 줄일 수 있다.
이 때, 숫자 n의 자리 수는 Math.log10() 메서드를 이용해 쉽게 구할 수 있다.
'Algorithm > 문제 풀이' 카테고리의 다른 글
[백준 / Java] 1697 - 숨바꼭질 (0) | 2023.05.28 |
---|---|
[프로그래머스 / Java] - 큰 수 만들기 (0) | 2023.05.24 |
[프로그래머스 / Java] - 호텔 대실 (0) | 2023.05.22 |
[프로그래머스 / Java] - 억억단을 외우자 (0) | 2023.05.19 |
[프로그래머스 / Java] - 두 원 사이의 정수 쌍 (0) | 2023.05.18 |
댓글