프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문자열을 일정한 단위로 잘라 연속되는 중복을 찾아 압축하고, 그 중 가장 짧은 결과물의 길이를 반환하는 문제입니다. 완전 탐색을 기반으로 하되, 파이썬의 슬라이싱과 zip 함수를 활용하여 효율적으로 구현하는 방법을 학습할 수 있습니다.
1. 나의 풀이
def solution(s):
answer = len(s)
# 문자열 길이가 2 이하인 경우 압축 효율이 없으므로 조기 반환
if len(s) <= 2:
return len(s)
# 1부터 문자열 절반 길이까지 단위를 늘려가며 확인
for i in range(1, len(s) // 2 + 1):
parts = []
idx = 0
# 설정된 단위 i만큼 문자열을 슬라이싱하여 parts 리스트에 저장
while idx + i <= len(s):
# 이전 조각과 동일하면 카운트 증가, 다르면 새로 추가
if parts and parts[-1][0] == s[idx:idx + i]:
parts[-1][1] += 1
else:
parts.append([s[idx:idx + i], 1])
idx += i
# 남은 잔여 문자열 길이 계산 (단위로 나누어 떨어지지 않는 뒷부분)
compressed_len = len(s[idx:])
# parts 리스트를 순회하며 최종 압축 길이 합산
for part in parts:
compressed_len += i
if part[1] > 1:
# 반복 횟수가 10회, 100회 이상일 경우를 대비하여 문자열 길이로 합산
compressed_len += len(str(part[1]))
answer = min(answer, compressed_len)
return answer
2. 오늘 배운 점 및 복기 노트
데이터를 묶어주는 zip 함수 활용법
파이썬의 내장 함수인 zip은 여러 개의 반복 가능한(iterable) 객체를 인자로 받아, 각 객체가 담고 있는 원소를 튜플 형태로 차례로 접근할 수 있게 합니다.
기본적인 사용법은 다음과 같습니다.
names = ['A', 'B', 'C']
scores = [10, 20, 30]
print(list(zip(names, scores))) # [('A', 10), ('B', 20), ('C', 30)] 형식입니다
for name, score in zip(names, scores):
print(f"{name}: {score}")
# 결과: A: 10, B: 20, C: 30
이번 문제와 같은 인접 원소 비교 패턴에서는 zip을 활용하여 '현재 원소'와 '다음 원소'를 쌍으로 묶어 처리할 수 있습니다.
# 인접 원소 비교 예시
words = ['ab', 'ab', 'cd', 'cd']
shifted_words = words[1:] + [''] # ['ab', 'cd', 'cd', '']
# words[1:] + ['']를 통해 한 칸씩 밀린 리스트와 비교 대상을 맞춤
for curr, nxt in zip(words, shifted_words):
if curr == nxt:
print(f"{curr}는 다음 요소와 같습니다.")
인덱스 제어와 슬라이싱의 관계 while 문을 사용하여 idx를 수동으로 증가시키는 방식은 인덱스 범위를 직접 제어하기에 용이하지만, 파이썬의 range(start, stop, step)를 활용하면 코드가 더 간결해질 수 있음을 확인했습니다. 특히 슬라이싱 s[idx:idx+i]에서 범위를 벗어나는 인덱스가 입력되어도 에러가 발생하지 않고 남은 부분까지만 반환한다는 파이썬의 특성을 이용하면 조건문을 줄일 수 있습니다.
range의 step 인자를 활용한 문자열 분할
문자열을 특정 간격(length)으로 자를 때, while 문을 쓰지 않고 리스트 컴프리헨션과 range의 세 번째 인자인 step을 활용하면 훨씬 간결하게 분할할 수 있습니다.
# s = "abcabcdede", length = 3 일 때
words = [s[i:i + length] for i in range(0, len(s), length)]
# 0부터 끝인덱스까지 한 도막(3)만큼 간격으로 자른 각 도막의 앞 인덱스가 i에 담김
# 결과: ['abc', 'abc', 'ded', 'e']
# -> [s[0:3], s[3:6], s[6:9], s[9:12]]가 담긴것
이 방식의 장점은 파이썬 슬라이싱의 특성상 마지막에 남는 문자열이 length보다 작더라도 인덱스 에러 없이 남은 부분만 정확히 가져온다는 것입니다. 수동으로 idx += length를 관리하는 것보다 실수를 줄일 수 있는 안전한 방법입니다.
3. 프로그래머스 코딩 테스트 문제 풀이 전략 교재에서 배울만한 점
교재에서는 크게 두 가지 풀이 흐름을 제시하며, 각각의 최적화 포인트가 다릅니다.
[첫 번째 풀이: 순차 비교 방식의 효율성]
교재의 첫 번째 풀이는 문자열을 실제로 합치지 않고 길이를 계산하는 것에 집중합니다. comp_len이라는 변수를 두고, 반복되는 패턴이 끝날 때마다 숫자의 길이(len(str(cnt)))와 패턴의 길이(len(temp))를 더해나갑니다. 이는 파이썬에서 무거운 작업인 문자열 연산(+)을 최소화하여 성능을 높이는 전략입니다.
[두 번째 풀이: 구조적 접근과 예외 처리]
두 번째 풀이는 모든 단위를 먼저 리스트로 만든 뒤 zip으로 처리합니다. 이 과정에서 발생할 수 있는 치명적인 오류를 짚어줍니다.
- 런타임 에러 방지: 문자열 s의 길이가 1일 때, range(1, len(s) // 2 + 1)은 빈 범위를 반환합니다. min() 함수에 빈 반복 가능 객체가 들어가면 에러가 발생하므로, if len(s) == 1: return 1과 같은 예외 처리가 반드시 선행되어야 함을 배울 수 있습니다.
'알고리즘 > 프로그래머스 문제 풀이 전략' 카테고리의 다른 글
| 문제9 - 짝지어 제거하기 (Python) (0) | 2026.04.23 |
|---|---|
| 문제8 - 튜플 (Python) (0) | 2026.04.23 |
| 문제7 - 이상한 문자 만들기 (Python) (0) | 2026.04.22 |
| 문제6 - 시저 암호 (Python) (0) | 2026.04.22 |
| 문제5 - 행렬의 곱셈 (Python) (0) | 2026.04.21 |
