BEFORE else: left = []
AFTER else: leftlist = []
처음에 문제를 읽고 멈췄다. IPv6이 뭔지는 알겠는데, 어디까지 생략할 수 있고 어디까지 복원해야 하는지가 직관적으로 와닿지 않았다. ::를 처음 봤을 때 "콜론이 두 개?" 하고 그냥 넘겼다가, 예제 출력을 보고 다시 문제를 정독했다. · · ·
IPv6 주소 복원
문제 소개 IPv6 주소는 원래 8개 그룹, 그룹당 16진수 4자리 형태다. 사람이 읽고 쓰기 편하도록 두 가지 규칙으로 줄여쓸 수 있다. 축약된 주소를 입력받아 원래 형태로 복원하는 것이 목표다.
::1 → 0000:0000:0000:0000:0000:0000:0000:0001
축약된 IPv6 주소를 32자리 16진수 원형으로 복원한다| 항목 | 내용 |
|---|---|
| 입력 | 올바른 축약형 IPv6 주소 (최대 39글자) |
| 출력 | 32자리 16진수 원형 IPv6 주소 |
| 핵심 도구 | split(), zfill(), join() |
| 난이도 | Silver I |
규칙 1 앞자리 0 생략 가능 각 그룹에서 앞쪽 0은 몇 개든 지울 수 있다.
뒤쪽 0은 절대 지우지 않는다. 0001 → 1 00aa → aa 0370 → 370 0000 → 0
뒤쪽 0은 절대 지우지 않는다. 0001 → 1 00aa → aa 0370 → 370 0000 → 0
규칙 2 연속된 0000 그룹을 :: 로 압축 0으로만 이루어진 연속 그룹 하나를
:: 하나로 치환할 수 있다.
:: 는 딱 한 번만 사용 가능. 2001:0000:0000:0001 → 2001::1 두 번 쓰면 모호해짐
:: 하나로 치환할 수 있다.
:: 는 딱 한 번만 사용 가능. 2001:0000:0000:0001 → 2001::1 두 번 쓰면 모호해짐
핵심 깨달음
aa를 복원하면 00aa다. aa00이 아니다.
앞쪽 0만 지울 수 있으므로, 복원할 때도 앞쪽에만 0을 붙인다. 바로 이것이 zfill(4)가 하는 일이다.
· · · 풀이 흐름 규칙을 이해하고 나면 구현은 크게 두 갈래로 나뉜다.
aa를 복원하면 00aa다. aa00이 아니다.
앞쪽 0만 지울 수 있으므로, 복원할 때도 앞쪽에만 0을 붙인다. 바로 이것이 zfill(4)가 하는 일이다.
1
:: 존재 여부 확인 if "::" in ip 로 분기한다.
2
:: 기준으로 좌우 분리 ip.split("::") 로 왼쪽 / 오른쪽 문자열을 얻는다.
3
각각을 : 기준으로 그룹 리스트 변환 빈 문자열이면 [] 빈 리스트로 처리. 이게 함정이다.
4
부족한 그룹 수만큼 "0000" 채우기 missing = 8 - (len(leftlist) + len(rightlist))
5
각 그룹을 4자리로 맞추기 group[i].zfill(4) 적용.
6
":" 로 합쳐서 출력 ":".join(groups)
⚠️ 핵심 함정 — 변수명 오타 leftlist = [] 로 써야 할 곳을
left = [] 로 잘못 썼다.
이렇게 하면 left 변수는 빈 리스트가 되지만,
아래에서 참조하는 건 leftlist 라서
leftlist는 여전히 [""] 상태로 남아
그룹 개수 계산이 1개 더 잡힌다.
① BEFORE / AFTER
left = [] 로 잘못 썼다.
이렇게 하면 left 변수는 빈 리스트가 되지만,
아래에서 참조하는 건 leftlist 라서
leftlist는 여전히 [""] 상태로 남아
그룹 개수 계산이 1개 더 잡힌다.
BEFORE
if left != "":
leftlist = left.split(":")
else: left = []
AFTER
if left != "":
leftlist = left.split(":")
else: leftlist = []
# 문자열 - IPv6 (백준 3107)
# https://www.acmicpc.net/problem/3107
ip = input()
if "::" in ip:
left, right = ip.split("::")
if left != "":
leftlist = left.split(":")
else:
leftlist = []
if right != "":
rightlist = right.split(":")
else:
rightlist = []
missing = 8 - (len(leftlist) + len(rightlist))
middle = []
for i in range(missing):
middle.append("0000")
for le in range(len(leftlist)):
leftlist[le] = leftlist[le].zfill(4)
for ri in range(len(rightlist)):
rightlist[ri] = rightlist[ri].zfill(4)
group = leftlist + middle + rightlist
else:
group = ip.split(":")
for i in range(len(group)):
group[i] = group[i].zfill(4)
result = ":".join(group)
print(result)
· · · 예제 검증 예제 1 — :: 없음
# 입력
25:09:1985:aa:091:4846:374:bb
# 각 그룹 zfill(4)
25 → 0025
09 → 0009
1985 → 1985
aa → 00aa
091 → 0091
4846 → 4846
374 → 0374
bb → 00bb
# 출력
0025:0009:1985:00aa:0091:4846:0374:00bb
예제 2 — :: 있음 (앞이 비어있는 케이스)
# 입력
::1
# split("::") 결과
left = "" # 빈 문자열 → leftlist = []
right = "1"
rightlist = ["1"] # 1개 그룹
missing = 8 - (0 + 1) = 7
# middle = ["0000"] * 7
# group = [] + ["0000"]*7 + ["0001"]
# 출력
0000:0000:0000:0000:0000:0000:0000:0001
· · · 핵심 함수 3개
.split(sep) sep 기준으로 나눠 리스트 반환 "a:b:c" .split(":") → ['a','b','c']
.zfill(n) 왼쪽에 0을 채워 n자리로 맞춤 "aa".zfill(4) → "00aa" "1".zfill(4) → "0001"
sep.join(lst) 리스트 원소를 sep로 이어붙임 ":".join( ['a', 'b'] ) → "a:b"
| 단계 | 복잡도 | 이유 |
|---|---|---|
| split | O(n) | 문자열 길이 n 순회 |
| zfill 루프 | O(1) | 최대 8개 그룹 × 4자리 상수 |
| join | O(1) | 최대 8개 그룹 고정 |
| 전체 | O(n) | 입력 문자열 길이에만 비례 |
이번 문제에서 가져가는 것
- 변수명을 정확하게. left와 leftlist는 다른 변수다. 이름이 비슷할수록 오타가 숨는다.
- 빈 문자열 처리를 항상 생각하자. "".split(":")는 []가 아니라 ['']다.
- 규칙 이해가 먼저다. IPv6 축약 규칙을 손으로 그려보고 코딩을 시작했더니 흐름이 훨씬 빠르게 잡혔다.
- zfill()은 앞쪽에만 0을 붙인다. 이 성질 하나가 이 문제의 핵심이었다.
'크래프톤 정글 > 정글에서 문제풀기' 카테고리의 다른 글
| [정글 알고리즘]-[중]-백준 10819 차이를 최대로 - DFS 백트래킹 (0) | 2026.03.10 |
|---|---|
| [정글 알고리즘]-[중] 골드바흐의 추측 (0) | 2026.03.10 |
| [정글 베이직 10] — 정수론- GCD & LCM (0) | 2026.03.09 |
| [정글 베이직 9]삽입 정렬 (Insertion Sort) 구현 (0) | 2026.03.09 |
| [정글 베이직 7] Big O 복잡도 분석 — 배열에서 중복 원소 찾기 (0) | 2026.03.09 |