[7785] 회사에 있는 사람
백준 Silver V | 7785 | Python | 문제 링크
문제 설명
직원들의 출입 로그가 순서대로 주어진다. enter이면 입장, leave이면 퇴장이다. 로그를 전부 처리한 뒤 현재 회사에 남아있는 사람을 역순 알파벳으로 출력한다.
입력
첫째 줄에 로그 수 n (1 ≤ n ≤ 1,000,000)이 주어진다. 이후 n줄에 이름과 enter 또는 leave가 주어진다.
출력
현재 회사에 있는 사람의 이름을 역순 알파벳으로 한 줄에 한 명씩 출력한다.
입출력 예
| 입력 | 출력 |
|---|---|
| 4 Baha enter Askar enter Baha leave Artem enter |
Askar Artem |
나의 풀이
풀이 1 - 버그 4개 들어있던 첫 제출
import sys
input = sys.stdin.readline
num = int(input())
current = {} # dict 사용
for _ in range(num):
record = input().split()
if record[1] == "enter":
current[record[0]] # 저장 안 함
if record[1] == "leave":
if current[record[1]]: # record[1]은 "leave"
del current[record[1]] # "leave" 키 삭제
else: pass
print("\n".join(current(keys))) # 문법 오류 다수
구조 자체는 그려졌다. 로그를 읽으면서 입장하면 추가하고, 퇴장하면 제거하면 된다. 그런데 코드를 다시 보니 버그가 한두 개가 아니었다.
버그 1 — 존재 여부만 필요한데 dict를 썼다
이름이 있는지 없는지만 알면 되는 상황이다. key-value 쌍이 필요 없으니 dict보다 set이 맞다. 당장 틀린 건 아니지만 불필요한 복잡도를 끌어들였다.
버그 2 — 입장 처리에서 저장을 안 한다
current[record[0]]
할당 없이 키에만 접근하고 있다. 없는 키면 KeyError가 나고, 있는 키면 값을 읽고 끝이다. current[record[0]] = True처럼 써야 하는 자리였다.
버그 3 — 인덱스를 잘못 썼다
if current[record[1]]:
del current[record[1]]
record[0]이 이름, record[1]이 "enter" 또는 "leave"다. 퇴장 처리에서 이름 대신 record[1], 즉 "leave" 문자열로 딕셔너리를 조회하고 삭제하고 있다. 사람 이름이 아니라 "leave"라는 키를 지우는 코드다.
이게 제일 황당했다. 로직은 맞게 생각했는데 인덱스가 뒤바뀌어 있었다.
버그 4 — 출력 문법이 전부 틀렸다
print("\n".join(current(keys)))
세 가지가 동시에 틀렸다. current는 딕셔너리인데 함수처럼 호출하고 있고, keys는 메서드라 keys()로 써야 하고, 역순 정렬도 빠져 있다.
풀이 2 — 1차 수정 후에도 출력이 틀렸다
import sys
input = sys.stdin.readline
num = int(input())
current = set()
for _ in range(num):
record = input().split()
if record[1] == "enter":
current.add(record[0])
if record[1] == "leave":
if record[0] in current:
current.remove(record[0])
print("\n".join(current.keys(), revers=True))
버그 1~3을 고쳐 set으로 바꾸고 인덱스도 잡았다. 그런데 출력에서 또 걸렸다.
set에는 keys()가 없다. dict 전용 메서드다. set은 그 자체로 이터러블이라 sorted(current)로 바로 쓰면 된다. 거기다 reverse를 revers로 오타까지 냈다.
풀이 3 - 최종 제출 코드
import sys
input = sys.stdin.readline
num = int(input())
current = set()
for _ in range(num):
record = input().split()
if record[1] == "enter":
current.add(record[0])
if record[1] == "leave":
current.discard(record[0])
print("\n".join(sorted(current, reverse=True)))
remove() 대신 discard()를 썼다. remove()는 없는 원소를 지우려 하면 KeyError가 나는데, discard()는 없으면 그냥 넘어간다. 로그 데이터가 항상 올바르다는 보장이 없으니 discard()가 더 안전하다. in 체크와 remove()를 따로 쓸 필요도 없어진다.