[문제해결 - 자료구조] BOJ1620 / 나는야 포켓몬 마스터 이다솜 / 실버4 (Python, 파이썬)

인생,개발중·2024년 3월 6일
0

알고리즘 문제

목록 보기
12/17

백준1620 문제 보러가기

문제

...(생략)

입력

첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면 물어봐도 괜찮아. 나는 언제든지 질문에 답해줄 준비가 되어있어.

둘째 줄부터 N개의 줄에 포켓몬의 번호가 1번인 포켓몬부터 N번에 해당하는 포켓몬까지 한 줄에 하나씩 입력으로 들어와. 포켓몬의 이름은 모두 영어로만 이루어져있고, 또, 음... 첫 글자만 대문자이고, 나머지 문자는 소문자로만 이루어져 있어. 아참! 일부 포켓몬은 마지막 문자만 대문자일 수도 있어. 포켓몬 이름의 최대 길이는 20, 최소 길이는 2야. 그 다음 줄부터 총 M개의 줄에 내가 맞춰야하는 문제가 입력으로 들어와. 문제가 알파벳으로만 들어오면 포켓몬 번호를 말해야 하고, 숫자로만 들어오면, 포켓몬 번호에 해당하는 문자를 출력해야해. 입력으로 들어오는 숫자는 반드시 1보다 크거나 같고, N보다 작거나 같고, 입력으로 들어오는 문자는 반드시 도감에 있는 포켓몬의 이름만 주어져. 그럼 화이팅!!!

출력

첫째 줄부터 차례대로 M개의 줄에 각각의 문제에 대한 답을 말해줬으면 좋겠어!!!. 입력으로 숫자가 들어왔다면 그 숫자에 해당하는 포켓몬의 이름을, 문자가 들어왔으면 그 포켓몬의 이름에 해당하는 번호를 출력하면 돼. 그럼 땡큐~
...(이하 생략)

예제 입력 1

26 5
Bulbasaur
Ivysaur
Venusaur
Charmander
Charmeleon
Charizard
Squirtle
Wartortle
Blastoise
Caterpie
Metapod
Butterfree
Weedle
Kakuna
Beedrill
Pidgey
Pidgeotto
Pidgeot
Rattata
Raticate
Spearow
Fearow
Ekans
Arbok
Pikachu
Raichu
25
Raichu
3
Pidgey
Kakuna

예제 출력 1

Pikachu
26
Venusaur
16
14

문제 해결

알맞은 자료구조, 오래 걸리지 않는 자료구조 찾기?

문제 자체는 간단하다.
입력값들을 어떤 틀 안에 넣은 뒤에 문자열을 입력 받으면, 그에 맞는 순서를, 숫자를 입력 받으면, 그에 맞는 문자열을 출력하면 된다.
여러가지 자료구조들을 생각했다.
리스트부터 해서 딕셔너리, 집합도 있었다.
나는 처음에 리스트로 구현하고자 했다. (파이썬에서 오래 걸리는 것을 알지만, 한 번 시도해보고 싶었다.)
리스트는 딕셔너리와 상관없이 순서대로 넣기만 하면, index가 key 값이 되기 때문에, 따로 설정할 필요가 없다고 생각했다.
그리고 해당 value에 맞게 index를 호출하는 index() 함수도 있기 때문에 답 자체는 쉽게 찾을 수 있을 것이라고 생각했다.
그래서 코드는 다음과 같이 짰다.

N, M = map(int, input().split())
poketmon = []
for _ in range(N) :
    poketmon.append(input())
    
for _ in range(M) :
    a = input()
    if a in poketmon :
        print(poketmon.index(a)+1)
    else :
        a = int(a)
        print(poketmon[a-1])

아니나 다를까, 시간 초과가 떴다.

python에서의 list의 index()

list에서 index() 함수는 최악의 경우 O(n)의 시간복잡도가 걸린다.
n은 리스트의 길이를 나타내는데, 리스트의 길이가 늘어나면 늘어날수록, index() 함수를 실행하는 데 필요한 시간도 증가하게 된다. 이는 index() 함수가 선형 탐색 알고리즘을 사용하기 때문이다.
찾고자 하는 요소가 리스트의 앞쪽에 위치한다면, 이보다 훨씬 빠른 시간 내에 결과를 얻을 수 있긴 하다.
선형 탐색 알고리즘은 List의 첫 번째 요소부터 확인하기 때문에 위와 같은 현상이 일어나는 것이다.

딕셔너리 활용

그러면 딕셔너리를 활용해보자.
딕셔너리는 key 값만 정확히 알고 있으면, 모든 데이터를 순회할 필요 없이 해시 함수를 통해 바로 접근할 수 있기 때문에 매우 빠른 속도로 데이터를 처리할 수 있다.(모든 키가 같은 해시 값을 가지지 않는 경우에서는 그렇다. 모든 키가 같은 해시 값을 가지면 그것은 최악의 경우이다.)
위 문제를 따르면, key 값에 문자열과, 숫자를 모두 저장해야 한다. 그 이유는 숫자에 따라 문자열을 반환해야 하는 경우도 있기 때문이다.
숫자인지를 확인하려면 isdigit() 함수를 사용하면 된다.
isdigit() 함수는 입력받은 '문자열' 데이터가 숫자로만 이루어져 있는지 검증할 때 사용된다.
그래서 코드는 다음과 같다.

N, M = map(int, input().split())
poketmon = {}
for i in range(N) :
    p = input()
    poketmon[i+1] = p # 숫자를 key, 문자열을 value
    poketmon[p]= i+1 # 문자열을 key, 숫자를 value
    
for _ in range(M) :
    a = input()
    if a.isdigit(): # 입력 받은 문자열이 숫자라면,
        print(poketmon[int(a)])
    else :
        print(poketmon[a])
profile
There are many things in the world that I want to do

0개의 댓글