본문 바로가기
Algorithm/프로그래머스

[프로그래머스][2020카카오공채] 문자열 압축 (level 2) (java)

by HBGB 2019. 12. 5.

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

 

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

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

programmers.co.kr

 
 
 

방법 1 : 길이만 구하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Solution {
    public int solution(String s) {
 
        if (s.length() <= 1) {
            return s.length();
        }
        
        int iMin = 1000;
 
        // 단위를 늘려가며 문자열 자르기 반복문
        for (int iUnit = 1; iUnit <= s.length() / 2; iUnit++) {
 
            int iBefore_Count = 1;
            int iSum = 0;
            int iUnitCount = (int) Math.ceil(s.length() / (double) iUnit);
            String strNow = "";
            String strNext = "";
            
            // 배열 현재값과 다음값 비교 반복문
            for (int i = 0; i < iUnitCount - 1; i++) {
                
                // 길이별로 복사해서 문자열 할당
                strNow = s.substring(i * iUnit, (i + 1* iUnit);
                strNext = ((i + 2* iUnit <= s.length()) 
                        ? s.substring((i + 1* iUnit, (i + 2* iUnit) 
                        : s.substring((i + 1* iUnit);
                
                // 같을 때
                if (strNow.equals(strNext)) {
                    
                    iBefore_Count++;
                    
                    if (i == iUnitCount - 2)  {
                        iSum += (iBefore_Count+"").length() + iUnit;
                    }
                    continue;
                }
                
                // 다를 때
                if (iBefore_Count == 1) {
                    iSum += iUnit;
                }
                if (iBefore_Count > 1) {
                    iSum += (iBefore_Count+"").length() + iUnit;
                }
                iBefore_Count = 1;
                
                if (i == iUnitCount - 2)  {
                    iSum += strNext.length();
                }
            }
 
            // 최소값
            if (iMin > iSum) {
                iMin = iSum;
            }
        }
        return iMin;
    }
}
Colored by Color Scripter
 

방법2 : 문자열을 구한 후 길이 구하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import java.util.ArrayList;
import java.util.List;
 
class Solution {
    public int solution(String s) {
        
        if (s.length() <= 1) {
            return s.length();
        }
        
        List<Integer> listLength = new ArrayList<Integer>();
        StringBuilder sb = null;
 
        // 단위를 늘려가며 문자열 자르기 반복문
        for (int iUnit = 1; iUnit <= s.length() / 2; iUnit++) {
 
            String[] arrStr = chop(iUnit, s);
            sb = new StringBuilder();
            int iBefore_Count = 1;
 
            // 배열 이전값과 현재값 비교
            for (int i = 1; i < arrStr.length; i++) {
 
                // 같을 때
                if (arrStr[i - 1].equals(arrStr[i])) {
                    iBefore_Count++;
                    continue;
                }
 
                // 다를 때
                if (iBefore_Count == 1) {
                    sb.append(arrStr[i - 1]);
                }
                if (iBefore_Count > 1) {
                    sb.append(iBefore_Count + arrStr[i - 1]);
                }
 
                iBefore_Count = 1;
            }
 
            // 마지막 문자열 처리
            if (iBefore_Count == 1) {
                sb.append(arrStr[arrStr.length - 1]);
            }
            if (iBefore_Count > 1) {
                sb.append(iBefore_Count + arrStr[arrStr.length - 1]);
            }
            
            // 리스트에 결과 문자열 길이저장
            listLength.add(sb.toString().length());
        }
 
        // 최소값 구하기
        int iMin = 1000;
 
        for (int i = 0; i < listLength.size(); i++) {
            if (iMin > listLength.get(i)) {
                iMin = listLength.get(i);
            }
        }
 
        return iMin;
    }
 
    // 문자열 자르기 -> 배열
    public String[] chop(int iUnit, String s) {
 
        if (iUnit == 1) {
            return s.split("");
        }
 
        int index = 0;
        String[] arrStr = new String[(int) Math.ceil(s.length() / (double) iUnit)];
 
        for (int i = 0; i < s.length(); i++) {
            if (i % iUnit == 0) {
                arrStr[index++= (i + iUnit <= s.length()) ? s.substring(i, i + iUnit) : s.substring(i);
            }
        }
        return arrStr;
    }
}
Colored by Color Scripter

 

당연히! 

방법 1이 방법 2보다 2배 빨랐다. 

 

생각해보면 문제에서 원하는 답은 '길이'이므로,

정확한 문자열까지는 구할필요가 없는 것이다.

하지만 처음부터 생각이 그에 닿지는 않아서

방법2로 먼저 통과하고 그제서야 방법1을 떠올렸다. 

 

 잡)

이 문제는 지난 9월 시험삼아 카카오 코딩테스트를 치러봤을때 처음 만났던 문제이다.

그때는 알고리즘 공부를 하기 전이었는데

7문제 5시간의 시험에서 딱 1문제라도 푸는게 목표였다.

 

그때 풀려고 시도했던게 이 문제였는데,

그때는 4시간ㅋㅋ 걸려서 구현 비스므리 한 것을 해내고도

테스트 케이스 3~4개에 걸려서 결국 틀렸다.

나중에야 이게 레벨1짜리 문제였다는 걸 알았는데 ㅋㅋ

 

지금은 더 효율적인 방법을 생각하려고 애쓰고 있으니

아주 만족스럽다 :)

 

 

 

댓글