크래프톤 정글/정글에서 문제풀기

[정글 알고리즘]- [중]- IPV6 (백준 3107번)

cedis 2026. 3. 9. 20:56

 

 

BEFORE else: left = []
AFTER else: leftlist = []

처음에 문제를 읽고 멈췄다. IPv6이 뭔지는 알겠는데, 어디까지 생략할 수 있고 어디까지 복원해야 하는지가 직관적으로 와닿지 않았다. ::를 처음 봤을 때 "콜론이 두 개?" 하고 그냥 넘겼다가, 예제 출력을 보고 다시 문제를 정독했다. · · ·
IPv6 주소 복원
::1 0000:0000:0000:0000:0000:0000:0000:0001
축약된 IPv6 주소를 32자리 16진수 원형으로 복원한다
문제 소개 IPv6 주소는 원래 8개 그룹, 그룹당 16진수 4자리 형태다. 사람이 읽고 쓰기 편하도록 두 가지 규칙으로 줄여쓸 수 있다. 축약된 주소를 입력받아 원래 형태로 복원하는 것이 목표다.
항목 내용
입력 올바른 축약형 IPv6 주소 (최대 39글자)
출력 32자리 16진수 원형 IPv6 주소
핵심 도구 split(), zfill(), join()
난이도 Silver I
· · · 규칙부터 잡았다 코드 이전에 규칙 2개를 머릿속에 완전히 박아야 한다.
규칙 1 앞자리 0 생략 가능 각 그룹에서 앞쪽 0은 몇 개든 지울 수 있다.
뒤쪽 0은 절대 지우지 않는다.
0001 → 1 00aa → aa 0370 → 370 0000 → 0
규칙 2 연속된 0000 그룹을 :: 로 압축 0으로만 이루어진 연속 그룹 하나를
:: 하나로 치환할 수 있다.
:: 는 딱 한 번만 사용 가능.
2001:0000:0000:0001 → 2001::1 두 번 쓰면 모호해짐
핵심 깨달음
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)
· · · 버그가 1개 있었다 로직을 다 짜고 돌려봤더니 ::1 케이스에서 결과가 이상했다.
⚠️ 핵심 함정 — 변수명 오타 leftlist = [] 로 써야 할 곳을
left = [] 로 잘못 썼다.

이렇게 하면 left 변수는 빈 리스트가 되지만,
아래에서 참조하는 건 leftlist 라서
leftlist는 여전히 [""] 상태로 남아
그룹 개수 계산이 1개 더 잡힌다.
① BEFORE / AFTER
BEFORE
if left != "":
    leftlist = left.split(":")
else: left = []
AFTER
if left != "":
    leftlist = left.split(":")
else: leftlist = []
딱 한 단어 차이였다. 하지만 이 한 단어가 missing 계산 전체를 틀리게 만들었다. · · · 최종 코드
# 문자열 - 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) 입력 문자열 길이에만 비례
· · ·
이번 문제에서 가져가는 것
  • 변수명을 정확하게. leftleftlist는 다른 변수다. 이름이 비슷할수록 오타가 숨는다.
  • 빈 문자열 처리를 항상 생각하자. "".split(":")[]가 아니라 ['']다.
  • 규칙 이해가 먼저다. IPv6 축약 규칙을 손으로 그려보고 코딩을 시작했더니 흐름이 훨씬 빠르게 잡혔다.
  • zfill()은 앞쪽에만 0을 붙인다. 이 성질 하나가 이 문제의 핵심이었다.