문자열 압축

이종호·2020년 10월 7일
0

알고리즘

목록 보기
12/18

문제

데이터 처리 전문가가 되고 싶은 "어피치"는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다.
최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자열에 서 같은 값이 연속해서 나타나는 것을 그 문자의 개수와 반복되는 값으로 표현하여 더 짧은 문자열로 줄여서 표현하는 알고리즘을 공부하고 있습니다.

간단한 예로 "aabbaccc"의 경우 2a2ba3c(문자가 반복되지 않아 한 번만 나타난 경우 1은 생략함)와 같이 표현할 수 있는데 이러한 방식은 반복되는 문자가 적은 경우 압축률이 낮다는 단점이 있습니다.
예를 들면, "abcabcdede"와 같은 문자열은 전혀 압축되지 않습니다. 어피치는 이러한 단점을 해결하기 위해 문자열을 1개 이상의 단위로 잘라서 압축하여 더 짧은 문자열로 표현할 수 있는지 방법을 찾아보려고 합니다.

예를 들어, "ababcdcdababcdcb"의 경우 문자를 1개 단뤼로 자르면 전혀 압축되지 않지만, 2개 단위로 잘라서 압축하다면 "2ababcdcd"로 표현할 수 있으며, 이때가 가장 짧게 압축하여 표현하는 방법이빈다.

다른 예로, "abcabcdede"와 같은 경우, 문자를 2개 단뤼로 잘라서 압축하면 "abcabc2de"가 되지만 3개 단뤼로 자른다면 "2abcdede"가 되어 3개 단위가 가장 짧은 압축 방법이 됩니다. 이때 3개 단위로 자르고 마지막에 남는 문자열은 그대로 붙여주면 됩니다.

압축할 문자열 s,가 매개변수로 주어질 때, 위에 설명한 방법으로 1개 이상 단위로 문자열을 잘라 압축하여 표현한 문자열 중 가장 짧은 것의 길이를 return하도록 solution함수를 완성해주세요.

제한 사항

  • s의 길이는 1이상 1,000 이하입니다.
  • s는 알파벳 소문자로만 이루어져 있습니다.

입출력 예시

aabbaccc -> 7
ababcdcdababcdcd -> 9

구현 계획

우선 완전탐색 방법을 이용해야하고,
min함수를 이용해서 계속 더 짧은 길이로 개선해야 할 듯 하다.

1부터 2부터 문자열 길이의 절반까지 1씩 증가하면서 압축된 문자열을 구하고
압축된 문자열의 길이와 이전까지 갱신된 길이를 비교해 짧은값을 result에 계속 담음으로써 문제를 해결 할 수 있지 않을까 싶다.

그럼 다시 문제는 압축된 문자를 어떻게 구할것인가 하는것인데
함수로 하자면 입력은 문자열 s 와 나눌 크기 size변수가 입력으로 주어질 것이다.

그럼 우선 문자열s에서 size만큼의 문자를 빼고
(이전에 s를 temp_s로 바꾸어야 할 듯 하다.)

나는 지금 문자열을 빼고 다음 것을 확인하련느 방식을 취하려고 하는데, 음.. 더 나은 방식이 있을까?

단순히 index만 가지고 이용하는 방법은 없을까?

비교는 동일하게 하되, 다른 패턴의 값이 나올 경우 숫자는 그 전까지 저장된 값에 // size를 하면 되지 않을까 싶다.

현재 정리된 결과에 의하면,

  • 1부터 절반까지를 step의 반복문으로 설정해서 돌린다.

  • index로 앞배열과 뒷배열을 구분하고, 구한 비교함수로 비교한다.

  • 같으면 count를 증가시키고, 틀리면 if문을 통해 count가 1초과인지 구분한다.

  • 1초과 라면, 해당 숫자를 앞에 붙이고 처음 시작 인덱스부터 마지막 인텍스 까지 를 새로운 배열에 넣는다.

  • 1초과가 아니라면, 그냥 그대로를 새로운 배열에 넣는다.

  • 그렇게 반복문을 쭉 처리하고 반복문을 끝나게되면 min을 통해 배열의 길이를 result에 넣는다.

# s = input()
s = 'ababcdcd'
s = 'aabbaccc'
s = 'ababcdcdababcdcd'
s = 'abcabcdede'
s = 'abcabcabcabcdededededede'
s = 'xababcdcdababcdcd'
result = len(s)
for step in range(1, len(s)//2+1):
    end = step
    new_str = ''
    count = 1
    for i in range(0, len(s), step):
        front_str = s[i:i + step]
        back_str = s[i + step:i + 2*step]
        if front_str == back_str:
            count += 1
            end += step
        else:
            if count > 1:
                new_str += str(count)+ s[i:i+step]
            else:
                new_str += s[i:i+step]
            end += step
            count = 1
    
    result = min(result, len(new_str))

print(result)

풀이

배열이 아니었기 때문에 back_str를 구할 때 인덱스에 대한 별다른 조건을 붙이지 않아도 되었다.
파이썬이 아니라면 더 고생했을 것 같다.

풀면서 굳이 파이썬인데 배열을 써야하나 싶어 문자열로 바꾸었다.
프로그래머스에 본 문제가 있어 등록해보았더니 맞았다.
start변수는 굳이 필요하지 않아 삭제했다.

다른 풀이를 보니 아주 고급기술을 사용하지 않는이상 비슷한 것으로 보였다.

아이디어 자체는 많이 어렵지 않지만 역시 구현하는 입장에서 매우 경험이 되는 문제이지 않았나 싶다.

종종 다시 풀어 봐서 내 구현속도를 높이고 싶다.

profile
열심히 사는 사람

0개의 댓글