프로그래머스 코딩테스트연습 문자열 압축

이번 문제는 도저히 생각안나서 하나씩 과정으로 풀어서 코드가 매우 더럽다.
코드를 짧고 간결하게 작성하게 되는 날까지 연습하자.

import java.util.*;
import java.util.stream.*;

class Solution {
    public int solution(String s) {
        int strLength = s.length();
        var answerList = new ArrayList<Integer>();
        
        for (int i = 1; i <= strLength / 2+1; i++) {
            var temp = new ArrayList<String>();
            var tempStr = s;
            while(!tempStr.isBlank()){
                if(i > tempStr.length()){
                    temp.add(tempStr);
                    break;
                }
                String subStr = tempStr.substring(0, i);
                tempStr = tempStr.substring(i);
                temp.add(subStr);
            }

            String previous = "";
            int num = 0;
            StringBuilder string = new StringBuilder();
            for(var str : temp){
                if(num == 0){
                    previous = str;
                    num++;
                    continue;
                }
                if (str.equals(previous)) {
                    num++;
                }else{
                    if (num == 1) string.append(previous);
                    else string.append(num).append(previous);
                    previous = str;
                    num = 1;
                }
            }
            if (num == 1) string.append(previous);
            else string.append(num).append(previous);
            answerList.add(string.length());
        }
        
        return answerList.stream().mapToInt(Integer::intValue).sorted().findFirst().getAsInt();
    }
}

설명

해당 글자 크기의 반 + 1 만큼 돌면서
1. 먼저 글자를 해당 개수 만큼 쪼갠다.
2. 그것을 바탕으로 전 문자열과 현재 문자열을 비교하여 같다면 num을 증가시킨다.

while(!tempStr.isBlank()){
    if(i > tempStr.length()){
        temp.add(tempStr);
        break;
    }
    String subStr = tempStr.substring(0, i);
    tempStr = tempStr.substring(i);
    temp.add(subStr);
}

여기서 i 는 문자열의 크기 / 2 + 1 까지 반복하는 인덱스다.
즉 쪼갤 글자 안의 크기다.

가공할 문자열이 빈 문자열이 아닐때 까지
만약 쪼갤 글자의 크기가 현재 남은 문자열의 크기보다 크다면
( substring을 해야 하는데 만약 남은 글자가 2 글자고 쪼개야되는 글자가 5글자면 예외가 던져진다 )
그 상태로 temp라는 리스트에 추가하고 반복을 종료한다.

아니라면 남은 문자열의 i 미만의 문자열을 temp라는 리스트에 넣고
남은 문자열의 상태를 i 부터 끝까지로 바꿔준다.

이렇게 해서 while이 끝날 때 System.out.println으로 확인해주면


잘 쪼개지는 것을 볼 수 있다.

이 하나의 글자가 나올때 마다 각각 전의 문자열과 현재 문자열을 비교해서
숫자와 글자를 넘겨주면 된다.

String previous = ""; // 이전의 글자
int num = 0; // 초기값은 0, 이후 0에 도달할 일이 없음.
StringBuilder string = new StringBuilder(); // 가공된 글자를 표현하기 위함 ( 결과 )

for(var str : temp){
    if(num == 0){
        previous = str;
        num++;
        continue;
    }
    if (str.equals(previous)) {
        num++;
    }else{
        if (num == 1) string.append(previous);
        else string.append(num).append(previous);
        previous = str;
        num = 1;
    }
}
if (num == 1) string.append(previous);
else string.append(num).append(previous);
answerList.add(string.length());

temp 리스트 안에 있는 문자만큼 반복을 돌면서
맨 처음 num이 0일 경우에는 이전의 글자를 현재 문자열로 하고 숫자를 증가 시키고 다음으로 넘어간다.
( 이후 num은 절대로 0이 되지 않는다. )
만약 문자열이 전의 문자열과 같다면 num을 증가 시킨다.

만약 문자열이 다르다면
num이 1인 경우는 1을 작성하면 안되므로 1을 제외한 이전의 문자만 결과 문자열 변수에 더해준다.
num을 다시 1로 바꿔주고 이전의 문자도 다시 값을 기입해준다.

if (num == 1) string.append(previous);
else string.append(num).append(previous);
answerList.add(string.length());

만약 반복을 돌면서 마지막 문자열이 ccc 인 경우도 있을 것이다
그 경우 반복을 돌면서 가공될 문자에 더해지지 못하기 때문에
반복이 끝난 후 마지막으로 문자열에 넣어주는 작업을 해주고
answerList에 가공이 끝난 문자열의 크기를 넣어준다.

return answerList.stream().mapToInt(Integer::intValue).sorted().findFirst().getAsInt();

answerList에는 글자의 크기들이 들어 있다.
리스트를 stream을 통하여 안에 들어있는 Integer형의 객체를 int로 변경해주고
오름차순으로 정렬 후 제일 처음에 나오는 원소를 int형으로 반환해준다.

느낀점

예전에는 하지도 못할 것 같던 코딩테스트들이 점점 풀리기 시작했다.
3단계까지 할 수 있도록 노력해보자.

좋은 웹페이지 즐겨찾기