개발 블로그
[Programmers/파이썬]프로그래머스(Lv.2) 압축 문제풀이 본문
문제 설명
압축
신입사원 어피치는 카카오톡으로 전송되는 메시지를 압축하여 전송 효율을 높이는 업무를 맡게 되었다. 메시지를 압축하더라도 전달되는 정보가 바뀌어서는 안 되므로, 압축 전의 정보를 완벽하게 복원 가능한 무손실 압축 알고리즘을 구현하기로 했다.
어피치는 여러 압축 알고리즘 중에서 성능이 좋고 구현이 간단한 LZW(Lempel–Ziv–Welch) 압축을 구현하기로 했다. LZW 압축은 1983년 발표된 알고리즘으로, 이미지 파일 포맷인 GIF 등 다양한 응용에서 사용되었다.
LZW 압축은 다음 과정을 거친다.
- 길이가 1인 모든 단어를 포함하도록 사전을 초기화한다.
- 사전에서 현재 입력과 일치하는 가장 긴 문자열 w를 찾는다.
- w에 해당하는 사전의 색인 번호를 출력하고, 입력에서 w를 제거한다.
- 입력에서 처리되지 않은 다음 글자가 남아있다면(c), w+c에 해당하는 단어를 사전에 등록한다.
- 단계 2로 돌아간다.
압축 알고리즘이 영문 대문자만 처리한다고 할 때, 사전은 다음과 같이 초기화된다. 사전의 색인 번호는 정수값으로 주어지며, 1부터 시작한다고 하자.
색인 번호123...242526단어 | A | B | C | ... | X | Y | Z |
예를 들어 입력으로 KAKAO가 들어온다고 하자.
- 현재 사전에는 KAKAO의 첫 글자 K는 등록되어 있으나, 두 번째 글자까지인 KA는 없으므로, 첫 글자 K에 해당하는 색인 번호 11을 출력하고, 다음 글자인 A를 포함한 KA를 사전에 27 번째로 등록한다.
- 두 번째 글자 A는 사전에 있으나, 세 번째 글자까지인 AK는 사전에 없으므로, A의 색인 번호 1을 출력하고, AK를 사전에 28 번째로 등록한다.
- 세 번째 글자에서 시작하는 KA가 사전에 있으므로, KA에 해당하는 색인 번호 27을 출력하고, 다음 글자 O를 포함한 KAO를 29 번째로 등록한다.
- 마지막으로 처리되지 않은 글자 O에 해당하는 색인 번호 15를 출력한다.
K | A | 11 | 27: KA |
A | K | 1 | 28: AK |
KA | O | 27 | 29: KAO |
O | 15 |
이 과정을 거쳐 다섯 글자의 문장 KAKAO가 4개의 색인 번호 [11, 1, 27, 15]로 압축된다.
입력으로 TOBEORNOTTOBEORTOBEORNOT가 들어오면 다음과 같이 압축이 진행된다.
현재 입력(w)다음 글자(c)출력사전 추가(w+c)T | O | 20 | 27: TO |
O | B | 15 | 28: OB |
B | E | 2 | 29: BE |
E | O | 5 | 30: EO |
O | R | 15 | 31: OR |
R | N | 18 | 32: RN |
N | O | 14 | 33: NO |
O | T | 15 | 34: OT |
T | T | 20 | 35: TT |
TO | B | 27 | 36: TOB |
BE | O | 29 | 37: BEO |
OR | T | 31 | 38: ORT |
TOB | E | 36 | 39: TOBE |
EO | R | 30 | 40: EOR |
RN | O | 32 | 41: RNO |
OT | 34 |
입력 형식
입력으로 영문 대문자로만 이뤄진 문자열 msg가 주어진다. msg의 길이는 1 글자 이상, 1000 글자 이하이다.
출력 형식
주어진 문자열을 압축한 후의 사전 색인 번호를 배열로 출력하라.
입출력 예제
msganswerKAKAO | [11, 1, 27, 15] |
TOBEORNOTTOBEORTOBEORNOT | [20, 15, 2, 5, 15, 18, 14, 15, 20, 27, 29, 31, 36, 30, 32, 34] |
ABABABABABABABAB | [1, 2, 27, 29, 28, 31, 3 |
사고 흐름
문제를 이해하는 데 시간이 좀 걸렸다. (예제보고 따라감)
-> 문자열에서 사전에 존재하는 가장 긴 문자열을 찾아 매칭하고 다음 문자열을 포함한 새로운 문자열을 사전에 추가한다
-> 문자열 활용 문제인건 알겠는데, 정규표현식을 사용할지, 슬라이싱을 사용할지 고민함
-> 투 포인터를 사용한 슬라이싱으로 문제해결
-> 사전 배열을 하나 만들고 거기다 추가하는 형식으로 진행
-> 사전에 존재하는 문자열을 찾고, 그 인덱스를 answer에 추가, 그리고 새로운 문자열은 사전에 추가
문제 핵심과 알고리즘
사전에서 최대 길이의 문자열을 찾는 문제이므로 문자열과 리스트 활용 문제
def solution(msg):
answer = []
dictionary = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N",
"O","P","Q","R","S","T","U","V","W","X","Y","Z"]
i, j = 0, 1
while j<=len(msg) :
while msg[i:j] in dictionary and j<=len(msg):
j+=1
answer.append(dictionary.index(msg[i:j-1]) + 1)
dictionary.append(msg[i:j])
i=j-1
return answer
문제 풀며 헤맸던 부분
1. while문 조건식
while문의 조건식을 적는게 오래걸렸다. 자꾸 마지막 인덱스가 잘못 들어가서 그걸 해결하는데 시간을 보냈다. 자꾸 출력하면서 안좋은 습관이 있는데, 차분히 생각하는 연습하자..ㅠ
다른 사람 풀이 참고하여 배운 점
def solution(msg):
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
d = {k:v for (k,v) in zip(alphabet, list(range(1,27)))}
answer = []
while True:
if msg in d:
answer.append(d[msg])
break
for i in range(1, len(msg)+1):
if msg[0:i] not in d:
answer.append(d[msg[0:i-1]])
d[msg[0:i]] = len(d)+1
msg = msg[i-1:]
break
return answer
이 풀이는 먼저 문자열로 사전을 선언했다. 리스트 초기화하는걸로 시간이 좀 걸렸는데 이렇게 해도 되는구나! 그리고 알파벳과 인덱스를 묶어서 딕셔너리를 만들었다. 나라면 직접 일일이 선언햇을텐데 이런 방법도 있는구나.. 그 이후의 코드는 비슷하다. 나는 while문을 썻지만 여기서는 for문으로 해당 문자열이 없다면 사전에 추가하는 형식으로 했다.
총평
문자열 활용 문제에서 while 문 조건식이나 if 조건식에 좀 약한 것 같다. 차분하게 생각하자..!
<개념 정리>
1. zip(): 여러 개의 순회 가능한 객체를 인자로 받고, 각 객체가 담고 잇는 원소를 튜플의 형태
nums=[1,2,3]
letters=["A","B","C"]
for pair in zip(nums, letters) :
print(pair)
#(1, 'A')
#(2, 'B')
#(3, 'C')
(2023/03/15에 다시 풀어본 코드)
def solution(msg):
dictionary=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z']
answer = []
i=-1
while i<=len(msg) :
i+=1
if msg[:i+1] not in dictionary: #사전에 해당 문자열이 없을때
dictionary.append(msg[:i+1]) #사전에 문자열 추가
answer.append(dictionary.index(msg[:i])+1)
msg=msg[i:] #사전에 넣은 문자열 앞부분 삭제
i=-1
answer.append(dictionary.index(msg)+1) #마지막에 추가하는거 잘 생각하기!
return answer
저번에는 투포인터를 사용해 문제를 풀었지만, 이번에는 문자열 슬라이싱을 활용해 문제를 풀었다. 마지막 인덱스가 안들아가서 수정하느라 조금 시간이 걸렸지만, 저번보다는 수월하게 푼 것 같다.
왜 마지막에 따로 추가를 해줘야 하냐면, 마지막에 남은 문자열은 무조건 사전에 존재하는 문자열이다. 따라서 정답에 추가를 못하고 while문 조건에 의해 끝나므로 따로 마지막에 추가를 해야한다. 이것을 생각하는게 중요할 것 같다!
'Algorithm' 카테고리의 다른 글
[백준/파이썬] 4693번<섬의 개수> 문제 풀이 (0) | 2023.03.01 |
---|---|
[Programmers/파이썬]프로그래머스(Lv.2) n진수 게임 문제풀이 (0) | 2023.02.28 |
[백준/파이썬] 2606번<바이러스> 문제 풀이 (0) | 2023.02.28 |
[백준/파이썬] 2178번<미로 탐색> 문제 풀이 (0) | 2023.02.28 |
[Programmers/파이썬]프로그래머스(Lv.1) 다트게임 문제풀이 (2) | 2023.02.27 |