https://school.programmers.co.kr/learn/courses/30/lessons/60057
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
📌 문제 설명
데이터 처리 전문가가 되고 싶은 "어피치"는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자열에서 같은 값이 연속해서 나타나는 것을 그 문자의 개수와 반복되는 값으로 표현하여 더 짧은 문자열로 줄여서 표현하는 알고리즘을 공부하고 있습니다.
간단한 예로 "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 | result |
"aabbaccc" | 7 |
"ababcdcdababcdcd" | 9 |
"abcabcdede" | 8 |
"abcabcabcabcdededededede" | 14 |
"xababcdcdababcdcd" | 17 |
✔️입출력 예에 대한 설명
입출력 예 #1
문자열을 1개 단위로 잘라 압축했을 때 가장 짧습니다.
입출력 예 #2
문자열을 8개 단위로 잘라 압축했을 때 가장 짧습니다.
입출력 예 #3
문자열을 3개 단위로 잘라 압축했을 때 가장 짧습니다.
입출력 예 #4
문자열을 2개 단위로 자르면 "abcabcabcabc6de" 가 됩니다.
문자열을 3개 단위로 자르면 "4abcdededededede" 가 됩니다.
문자열을 4개 단위로 자르면 "abcabcabcabc3dede" 가 됩니다.
문자열을 6개 단위로 자를 경우 "2abcabc2dedede"가 되며, 이때의 길이가 14로 가장 짧습니다.
입출력 예 #5
문자열은 제일 앞부터 정해진 길이만큼 잘라야 합니다.
따라서 주어진 문자열을 x / ababcdcd / ababcdcd 로 자르는 것은 불가능합니다.
이 경우 어떻게 문자열을 잘라도 압축되지 않으므로 가장 짧은 길이는 17이 됩니다.
🗒 풀이
def solution(s):
answer = []
for i in range(1, len(s) + 1):
temp_str = ''
cnt = 1
temp = s[:i]
for j in range(i, len(s) + i, i):
if temp == s[j: j + i]:
cnt += 1
else:
if cnt > 1:
temp_str += str(cnt) + temp
else:
temp_str += temp
cnt = 1
temp = s[j: j + i]
answer.append(len(temp_str))
return min(answer)
각 값을 비교하기 위한 answer 리스트 변수를 생성한다.
한 개 이상의 단위로 자르기 위해 1부터 문자열 s의 길이만큼 for문 탐색을 한다.
temp_str은 생성한 문자열, 즉 2a3ba3c 등을 저장하기 위한 임시 문자열 변수이다.
cnt는 중복된 문자열인지 아닌지를 판별하기 위한 변수이고, temp는 문자열 s를 i개의 단위로 자른 임시 문자열이다.
두 번째 for문에서는 s 문자열의 i부터 문자열 s의 길이를 i 단위로 건너뛰면서 temp문자열과 i 번째 뒤의 문자열이 중복된 것이 있는지, 없는지를 판단하는 함수이다. 이때 주의해야 할 것은 end point를 문자열 s의 길이에서 i 만큼 더해줘야 한다는 것이다.
만약 temp 문자열이 i번째 뒤의 문자열과 같은 것이 있다면, 중복된 것이 있다는 뜻이므로 cnt의 값을 하나씩 올려준다.
만약 중복이 없거나 끝난 경우(바깥 else)에서는 cnt > 1 즉 중복이 있는 경우는 임시 문자열 temp_str에 몇 개의 temp 문자열이 반복되었는지 cnt를 붙여줘 temp_str에 저장한다.
중복이 없는 경우는 그냥 temp 문자열을 저장한다.
j의 for문이 종료되면, cnt값을 초기화하고, temp는 그다음 문자열로 저장한다.
우리가 필요한 것은 문자열이 아닌, 문자열의 길이이므로, temp_str의 길이를 answer에 저장한다.
마지막으로 min() 함수를 사용하여 answer 배열에서 가장 작은 숫자, 즉 압축이 잘 되어 제일 짧은 길이를 반환한다.
🤔 후기
일단 공책에 문제를 찬찬히 읽어보며, 각각의 입출력 예를 적어보았다.
처음에는 abcabcdede같은 경우에는 2abc2de가 왜 안되지?라고 생각했으나, 여러 가지 입출력 예를 보면서 동일한 길이로만 압축이 된다는 것을 알았다. 즉 2개 단위의 문자열로만 (abcabc2de), 혹은 3개 단위의 문자열로만(2abcdede) 자를 수 있는 것이다.
문제가 이해가 되었고, 그냥 처음부터 탐색하는 방법밖에 없겠구나 싶었다.
하나의 문자열을 만들고 뒤의 것들과 비교하고, 더 이상 중복이 아닌 문자열이 나타나면 그 문자열을 가지고 또 탐색하고 이런 식으로 말이다.
그리고 위에서 찾아낸 동일 단위의 문자열로만 탐색할 수 있다는 규칙을 써먹기 위해 for j in range(i, len(s) + i, i)로 range의 3번째 인수로 i를 지정함으로써 i만큼의 단위씩으로만 탐색할 수 있도록 지정했다.
문제만 잘 이해하면 어렵지 않게 짤 수 있었는데, 문제 이해하는 게 좀 까다롭지 않았나 싶다.
'알고리즘' 카테고리의 다른 글
[백준] 2609번: 최대공약수와 최소공배수(java, python) (2) | 2022.09.20 |
---|---|
Big-O cheat sheet (0) | 2022.09.01 |
[프로그래머스] 오픈채팅방(python) (0) | 2022.08.20 |
[프로그래머스] 없는 숫자 더하기(python) (0) | 2022.08.20 |
[프로그래머스] 음양 더하기(python) (0) | 2022.08.14 |