문제 설명
윤수와 정환은 「전주 듣고 노래 맞히기」라는 게임을 할 예정이다. 「전주 듣고 노래 맞히기」는 주어진 노래의 전주를 듣고 먼저 제목을 맞히는 사람이 점수를 얻어 최종적으로 점수가 더 많은 사람이 이기는 게임이다. 절대 음감을 가진 윤수는 노래의 첫 네 음만 듣고도 어떤 노래든 바로 맞힐 수 있다. 따라서, 정환은 윤수를 이기기 위해 첫 세 음만으로 노래를 맞히게 해주는 프로그램을 만들려고 한다. 우선 정환이 알고 있는 노래 제목, 음이름 등을 데이터로 만든 뒤 프로그램을 구현하기 시작했다. 예를 들어, 다음은 TwinkleStar
(반짝반짝 작은 별)의 악보 중 일부이다.
위 악보를 박자와 관계없이 음이름으로 표현하면 CCGGAAG
가 된다.
윤수를 이기기 위해서는 이 프로그램이 첫 세 음인 CCG
만으로 노래 제목인 TwinkleStar
를 출력할 수 있어야 한다. 또한, 세상의 모든 노래를 아는 윤수와 다르게 정환은 음을 아는 노래가 N개뿐이다. 그래서 프로그램에 N개의 노래의 정보를 저장해 놓을 것이다. 만약 저장된 노래 중 입력한 첫 세 음으로 시작하는 노래가 여러 개 있어 무슨 노래인지 정확히 알 수 없는 경우 ?
를 출력하고, 입력한 첫 세 음에 맞는 저장된 노래가 없을 경우 !
를 출력한다.
정환을 도와서 첫 세 음만으로 본인이 음을 아는 노래를 맞히는 프로그램을 완성하자. 이 프로그램은 대문자와 소문자를 구분한다.
- 입력
첫 번째 줄에 정환이 음을 아는 노래의 개수 N, 정환이 맞히기를 시도할 노래의 개수 M이 공백으로 구분되어 주어진다.
두 번째 줄부터 N개의 줄에 걸쳐 노래 제목의 길이 $T$, 영어 대소문자로 이루어진 문자열 노래 제목 S, 해당 노래에서 처음 등장하는 일곱 개의 음이름 a_1, a_2, a_3, a_4, a_5, a_6, a_7이 공백으로 구분되어 주어진다.
N+2번째 줄부터 M개의 줄에 걸쳐 정환이 맞히기를 시도할 노래의 첫 세 음의 음이름 b_1, b_2, b_3가 공백으로 구분되어 주어진다.
주어지는 음이름은 각각 C
, D
, E
, F
, G
, A
, B
중 하나이다. 같은 제목이 두 번 이상 주어지지 않는다.
- 출력
정환이 맞히기를 시도할 각 노래에 대하여 프로그램에 저장된 노래와 첫 세 음이 동일한 노래가 하나만 있다면 해당 노래의 제목을, 두 개 이상이면 ?
을, 없다면 !
을 한 줄에 하나씩 출력한다.
<내 코드>
import sys
# N, M 입력
N, M = sys.stdin.readline().split()
a_dict = {}
b_count = {}
count = 0
# N 입력
for i in range(int(N)):
T, S, *a = sys.stdin.readline().split()
a = "".join(a)[:3]
# list에 넣는방법
if a in a_dict:
a_dict[a].append(S)
else :
a_dict[a] = [S]
# M 입력
for j in range(int(M)):
b_list = sys.stdin.readline().split()
b = "".join(b_list)
if b in a_dict:
if len(a_dict[b]) > 1:
print("?")
else :
print(a_dict[b][0])
else :
print("!")
1. 처음에는 리스트로 생각했다가 제목 출력을 위해 딕셔너리로 방식을 변경함
2. *a 로 split() 했을 때 디스트럭쳐링 방식이 있음을 알게됨
3. 필요한 부분만 슬라이싱으로 함
- 반성
1. 리스트 슬라이싱을 하면 같은 key 가 있을 수 있는데 이 부분에 대해서 딕셔너리 value 를 list로 넣는 방법을 익히게 됨
2. 딕셔너리의 장점에 대해서 생각하자 O(1) 로서 빠르게 검색이 가능
a = "".join(a)[:3] 부분이 a_key = "".join(a[:3])
이렇게도 가능함
<모범 사례>
import sys
from collections import defaultdict
input = sys.stdin.readline
# N, M 입력
N, M = map(int, input().split())
a_dict = defaultdict(list)
# N개의 노래 정보 입력
for _ in range(N):
T, S, *a = input().split()
a_key = "".join(a[:3]) # 첫 세 음으로 키 생성
a_dict[a_key].append(S)
# M개의 시도 입력 및 결과 출력
results = []
for _ in range(M):
b_key = "".join(input().split())
# 첫 세 음에 맞는 노래를 찾는 조건 분기
if b_key not in a_dict:
results.append("!") # 해당 키가 없으면 "!"
elif len(a_dict[b_key]) == 1:
results.append(a_dict[b_key][0]) # 유일한 노래가 있으면 제목 출력
else:
results.append("?") # 여러 개의 노래가 있으면 "?"
# 한 번에 출력
sys.stdout.write("\n".join(results) + "\n")
거의 비슷함
<보충 학습>
1. 리스트를 value로 넣는 방법 익히기
2. defaultdict 이용하기
keyError 방지에 유용 -> key가 없을 때 자동으로 기본값 설정해
a_dict = {}
if 'key' not in a_dict:
a_dict['key'] = []
a_dict['key'].append('value')
이 방식으로 if 문을 사용해서 []를 넣는대신에
from collections import defaultdict
a_dict = defaultdict(list)
a_dict['key'].append('value') # 키가 없으면 자동으로 리스트 초기화 후 추가
list 로 한번에 넣기 가능
default 인자에다가 자료형을 넣으면 value가 자동으로 세팅이 됨
'문제풀이 > 일일연습문제' 카테고리의 다른 글
[hash]99클럽 코테 스터디 9일차 TIL + 백준/Bronze/9933. 민균이의 비밀번호 (0) | 2024.11.06 |
---|---|
[array]99클럽 코테 스터디 8일차 TIL + 백준/Bronze/25593. 근무 지옥에 빠진 푸앙이 (Small) (0) | 2024.11.05 |
[hash]99클럽 코테 스터디 6일차 TIL + 백준/Bronze/27160. 할리갈리 (0) | 2024.11.03 |
[hash]99클럽 코테 스터디 5일차 TIL + 백준/Bronze/9094. 수학적 호기심 (1) | 2024.11.01 |
[string]99클럽 코테 스터디 4일차 TIL + 프로그래머스/1/81301. 숫자 문자열과 영단어 (1) | 2024.11.01 |