문제 보기 · Level 2 · 2019 KAKAO BLIND RECRUITMENT · 정답률 59% · 푼 사람 40,108명 (2026-09-30 기준)1

문제

채팅방 기록이 "Enter uid 닉네임", "Leave uid", "Change uid 닉네임" 꼴로 주어진다. 사용자는 uid로 구분한다. 닉네임이 바뀌면 이미 나온 메시지의 닉네임도 모두 새 닉네임으로 바뀐다. 모든 기록을 처리한 뒤 관리자가 보게 되는 "○○님이 들어왔습니다.", "○○님이 나갔습니다." 메시지 목록을 돌려준다.

  • 기록 1~100,000개
  • uid와 닉네임은 대소문자를 구분한다

풀이

막히면 한 단계씩 펼친다.

필요한 개념

딕셔너리와 집합: uid → 최종 닉네임 표.

1단계 · 작은 예로 손으로 풀기

기록 [“Enter u1 A”, “Enter u2 B”, “Change u1 C”, “Leave u2”]

  • 들어오고 나간 사건만 메시지가 된다: u1 들어옴, u2 들어옴, u2 나감
  • 마지막에 u1의 이름은 C, u2의 이름은 B다
  • 그래서 화면은 [“C님이 들어왔습니다.”, “B님이 들어왔습니다.”, “B님이 나갔습니다.”]

메시지에 적힌 이름은 그때의 이름이 아니라 맨 마지막 이름이다.

2단계 · 가장 단순한 방법과 그 속도

메시지를 만들어 두고, 이름이 바뀔 때마다 지금까지의 메시지를 모두 훑어 고치는 방법이 있다. 기록이 10만 개면 최악에 10만 × 10만 = 100억 번이다. 안 된다.

3단계 · 핵심 아이디어

메시지에 이름을 바로 적지 말고 uid만 적어 둔다. 이름은 마지막에 한 번만 채운다.

  1. 첫 번째 훑기: uid → 이름 딕셔너리를 Enter와 Change 때마다 덮어쓴다. 끝나면 모두 최종 이름이다. 동시에 Enter·Leave 사건을 (uid, 들어옴/나감)으로 모은다.
  2. 두 번째 훑기: 모은 사건마다 딕셔너리에서 최종 이름을 꺼내 문장을 만든다.

떠올리는 신호: “나중에 바뀐 값이 앞의 결과에도 반영된다” → 결과를 마지막에 만들고, 그때 최종 값을 찾는다.

4단계 · 코드 흐름
  1. 빈 딕셔너리 name과 사건 리스트 events를 만든다.
  2. 기록마다 빈칸으로 나눈다. Enter면 이름을 적고 (uid, 들어옴)을 모은다. Leave면 (uid, 나감)을 모은다. Change면 이름만 적는다.
  3. 사건마다 name[uid]로 문장을 만든다.
5단계 · 파이썬 코드
def solution(record):
    name = {}                               # uid → 최종 닉네임
    events = []                             # (uid, 들어옴/나감) 차례대로
    for r in record:
        parts = r.split()
        action, uid = parts[0], parts[1]
        if action in ("Enter", "Change"):
            name[uid] = parts[2]            # 이름은 계속 덮어쓴다
        if action == "Enter":
            events.append((uid, "들어왔습니다."))
        elif action == "Leave":
            events.append((uid, "나갔습니다."))
    return [f"{name[uid]}님이 {msg}" for uid, msg in events]
  • parts[2]: Leave에는 닉네임이 없으니 Enter·Change일 때만 꺼낸다.
  • action in ("Enter", "Change"): 둘 중 하나인지 본다.
  • 마지막 줄의 리스트 컴프리헨션이 두 번째 훑기다.
6단계 · 실행 추적

기록: Enter uid1234 Muzi / Enter uid4567 Prodo / Leave uid1234 / Enter uid1234 Prodo / Change uid4567 Ryan

기록 name events에 넣은 것
Enter uid1234 Muzi {1234: Muzi} (1234, 들어옴)
Enter uid4567 Prodo {1234: Muzi, 4567: Prodo} (4567, 들어옴)
Leave uid1234 그대로 (1234, 나감)
Enter uid1234 Prodo {1234: Prodo, 4567: Prodo} (1234, 들어옴)
Change uid4567 Ryan {1234: Prodo, 4567: Ryan} 없음

결과: Prodo 들어옴, Ryan 들어옴, Prodo 나감, Prodo 들어옴

7단계 · 복잡도와 흔한 실수

기록을 두 번 훑으니 \(O(n)\)이다.

  • Change에도 메시지를 만든다. 이름 바꾸기는 메시지가 없다.
  • Leave 기록에서 닉네임을 꺼내려다(parts[2]) 오류가 난다.
  • 다시 들어올 때(Enter) 새 닉네임을 쓰는 것도 이름 바꾸기라는 점을 놓친다.
검증: 문제의 예시를 통과했고, 무작위 기록 2,000묶음에서 “이름이 바뀔 때마다 앞의 메시지를 모두 고쳐 쓰는” 느린 풀이와 결과가 같았다 — 04_pg42888_p1.py
  1. 프로그래머스 스쿨, “오픈채팅방” (https://school.programmers.co.kr/learn/courses/30/lessons/42888), 2026-09-30 조회. ↩