Algorithm/Programmers

[2020 kakao blind recruitment] lv2 문자열 압축(cpp/python)

  • -
728x90

 

문자열 압축

 

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

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

programmers.co.kr

문제 설명

주어지는 문자열을 특정 길이만큼 잘라서 같은 문자면 숫자로 바꿔 표시했을 때의 (1은 생략) 그 문자열의 길이가 가장 짧은 순간을 찾는 문제

 

처음에는 1부터 주어지는 문자열의 길이만큼 자를 길이를 늘려가며 모두 탐색해야하나 싶었지만, 잘 생각해보면 해당 길이만큼의 중복되는 문자열을 찾는 것이므로, 문자열의 길이/2만큼만 탐색하면된다.

 

문제 풀이

소스코드 : C++

예전 풀이

#include<iostream>
#include <string>
#include <vector>
#include <queue>
#include<algorithm>

using namespace std;

int solution(string s) {
    int answer = s.size();
    for (int len = 1; len < s.size(); len++) {    //스플릿 길이
        int res = 0;
        string test;
        queue<pair<string, int>> q;
        q.push({ s.substr(0, len),0 });
        while (!q.empty()) {
            string cur = q.front().first;
            int idx = q.front().second;
            q.pop();
            int cnt = 0;
            for (int i = idx; i < s.size(); i += cur.size()) {
                string tmp = s.substr(i, cur.size());
                if (cur != tmp) {
                    q.push({ tmp,i });
                    break;
                }
                else {
                    cnt++;
                }
            }
            if (cnt > 1) res += to_string(cnt).size();
            test += cur;

            res += cur.size();
        }
        answer = min(res, answer);
    }
    return answer;
}

 

 

큐에 비교할 문자와 시작 인덱스를 넣어주고, 탐색을 시작한다. 현재 비교대상인 문자열(cur)과 for문에서 비교할 문자열을 잘라가며 비교해준다.

 

만약 현재 비교대상인 문자열(cur)과 자른 문자열(tmp)와 다르다면 그 문자열을 큐에 담아 다시 비교한다. 만약 같다면 개수를 증가시켜준다.

 

큐에 대한 반복문이 다시 실행되기 전에 비교했던 문자열의 개수와 길이를 이용하여 만들어질 문자열의 길이를 누적해준다. (aaa -> 3a라면 그냥 2를 누적해준다, 문자열을 직접 새로 만들어 마지막에 그 사이즈를 갱신시켜줘도 되겠지만, 그냥 길이만 생각해줘도 된다.)

 

이를 반복하여 자를 길이를 1씩 늘려주며 다시 반복하고 answer에 최솟값을 갱신한다.  

 

최근 풀이

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int solution(string s) {
    int answer = s.size();
    int len = 1;    // 자를 길이
    while(len <= s.size() / 2){
        int tmp = 0;    // 현재 탐색중인 문자열의 길이
        string cur = s.substr(0,len);// 현재 기준 문자열
        int l = len, cnt = 1;
        while(1){
            if(cur == s.substr(l,len))cnt++;
            else{
                if(cnt==1)tmp+=len;
                else tmp += to_string(cnt).size() + len;
                cur = s.substr(l,len);
                cnt = 1;
            }
            if(l+len>=s.size()){
                if(cnt==1)tmp+=s.size() - l;
                else tmp += to_string(cnt).size() + s.size() - l;
                break;
            }
            l+=len;
        }
        answer = min(answer, tmp);
        len++;
    }
    return answer;
}

이번에는 큐를 이용하지않고 투 포인터 방식과 비슷하게 적용하였다.

 

큐 대신에 갱신되는 것은 cur, cur과 s.substr(l,len) 과 같으면 cnt를 증가시켜주고, 그렇지 않다면 cur에 새로운 문자열을 갱신시켜주고 tmp에 현재까지의 길이를 누적시켜준다.

 

예전풀이에서는 cnt=0부터 시작하여 비교하지 않아도 될 비교를 1번씩 더했었지만 이번에는 비교 대상 자체는 비교할 필요없이 그냥 cnt=1부터 시작하여 풀이하였다.

 

그리고 if(l+len>=s.size())이 부분은 자를길이(len)으로 모두 자르고 남은 부분 (len 보다 짧은 길이가 남았을 때)를 처리해주는 부분이다.

 

예전 풀이 최근 풀이

최근 풀이가 좀 더 빠를거라고 생각했는데, 예전 풀이가 조금 더 빠른 것 같다. 또 모든 테케에 대해 예전풀이가 더 빠르지도 않다. 흠.. 왜일까...

 

소스코드 : Python

c++ 최근 풀이와 같다.  

def solution(s):
    answer = len(s)
    for i in range(1, len(s)//2 + 1):
        cur = s[0:i]
        cnt = 1
        l = i
        tmp = 0
        while 1:
            next_str = s[l:l+i]
            if next_str == cur: cnt+=1
            else:
                if cnt!=1: tmp+=len(str(cnt))
                tmp += i
                cur = next_str
                cnt = 1
            
            if l+i>=len(s):
                if cnt!=1: tmp += len(str(cnt))
                tmp += len(s) - l
                break
            l+=i
        answer = min(answer, tmp)

    return answer

 

728x90
300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.