문제
https://programmers.co.kr/learn/courses/30/lessons/43163
문제 설명
두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.
1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다. 2. words에 있는 단어로만 변환할 수 있습니다.
예를 들어 begin이 hit, target가 cog, words가 [hot,dot,dog,lot,log,cog]라면 hit -> hot -> dot -> dog -> cog와 같이 4단계를 거쳐 변환할 수 있습니다.
두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.
제한사항
- 각 단어는 알파벳 소문자로만 이루어져 있습니다.
- 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
- words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
- begin과 target은 같지 않습니다.
- 변환할 수 없는 경우에는 0를 return 합니다.
입출력
begin | target | words | return |
hit | cog | [hot, dot, dog, lot, log, cog] | 4 |
hit | cog | [hot, dot, dog, lot, log] | 0 |
알고리즘
def comparison(str1, str2):
answer = 0
for i in range(len(str1)):
if str1[i] == str2[i]:
answer += 1
if answer == len(str1)-1:
return True
else:
return False
def bfs_solution(begin, target, words):
# target이 words안에 없다면 단어 변환을 할 수 없으므로 0을 리턴한다.
if target not in words:
return 0
# 딕셔너리를 선언한다.
# 이 딕셔너리의 key는 각 단계를 나타내는 정수이고, value는 그 단계에서 만들수 있는 모든 단어의 배열이다.
graph = dict()
graph[0] = [begin]
# i는 graph의 key로 들어갈 값이다. 즉, 각 단계를 나타낸다. 그리고 temp배열을 만들어놓는다.
for i in range(1, len(words)):
print("i: ", i)
temp = []
# j라는 인덱스는 i-1번째 단계의 value, 즉 i-1번 변환해서 만들 수 있는 단어들의 배열을 순회한다.
# 각 원소를 comp로 지정한다.
for j in range(len(graph[i-1])):
print("j:", j)
comp = graph[i-1][j]
# k라는 인덱스는 words배열의 다른 단어들을 순회한다.
for k in range(len(words)):
print("k: ", k)
# words의 단어들을 순회하면서, comp와 comparison했을 때 True인 원소들을 temp에 append한다.
if comparison(comp, words[k]):
temp.append(words[k])
# temp 안에 target이 있다면, i를 리턴한다
if target in temp:
return i
# 그렇지 않다면, graph의 key인 i에 value로써 temp를 지정한다.
graph[i] = temp
설명
이 문제를 풀기 위해서 BFS를 사용했다. 너비 우선 탐색을 하면서, 다음 단계에 만들 수 있는 단어들 중에 target이 있다면 그 순간 결과를 return하면 되기 때문이다. dfs처럼 그래프의 리프노드까지 갈 필요가 없다.
내가 만들고자 한 데이터 형태는 다음과 같다.
key (start 단어에서 단어를 변환한 횟수) |
value (start단어에서 key만큼 단어를 변환할때 만들 수 있는 단어들의 배열) |
|
0 | [hit] | hit이라는 단어를 0번 변환하면 hit밖에 얻을 수 없다. |
1 | ['hot'] | hit을 1번 변환해서 얻을 수 있는 단어들의 배열이다 |
2 | ['dot', 'lot'] |
hit을 2번 변환해서 얻을 수 있는 단어들의 배열이다 |
3 | ['hot', 'dog', 'lot', 'hot', 'dot', 'log'] | hit을 3번 변환해서 얻을 수 있는 단어들의 배열이다 또한, ['dot', 'lot']를 1번 변환해서 얻을 수 있는 단어들의 배열이기도 하다. |
4 | ['dot', 'lot', 'dot', 'log', 'cog', 'hot', 'dot', 'log', 'dot', 'lot', 'hot', 'dog', 'lot', 'dog', 'lot', 'cog'] | 단어를 4번 변환했을 떄 cog라는 tarrget단어를 얻을 수 있다. 따라서, 4가 정답이다. |
위처럼 만들기 위해, 3중 for문을 사용했다. 시간 복잡도가 걱정되지만, 달리 방법을 찾지 못했다. 그리고 입력 단어의 갯수도 50개 미만이라 괜찮을 거라 생각했다.
- 인덱스 i, j, k를 사용한다. i를 사용해서 각 단계에 해당하는 key를 생성해서 graph의 key로 지정하고,
- j를 사용해서 그 전 단계의 value를 불러온다
- 그 불러온 전 단계 value의 원소들을 words와 비교해서, 그 다음 단계의 배열을 만들어서 graph[i]의 value로 지정한다.
- 그리고, 새로 만들어진 배열에 target단어가 있다면 i를 리턴한다.
결과
올바른 결과를 출력한다. 맨 밑줄에 출력된 4가 정답이다. 사진이 옆으로 길어서 좀 안보이는데, 위에 출력된 것들은 딕셔너리 형태의 graph이다. 자세히 보고싶으면 위에 표 참조하셈
후기
이거 dfs로 푸는줄알고 몇시간을 삽질을 하다가 도저히 안될것같아서 bfs로 해봤는데, 갑자기 딕셔너리 생각이 나서 이렇게 풀었다. 으으 진짜 삽질을 너무해가지고 개짱났다. 근데 이렇게 푸니까 엄청 깔끔하게 잘 풀린거같은 느낌이다.
이건 dfs로 풀 필요가 없다. 왜냐면 정해진 데이터의 leaf노드까지 가면서 탐색할 필요가 전혀 없기 때문이다. 그냥 만들 수 있는 단어들을 전부다 만들어 보면서, 원하는 단어가 나오면 거기서 return하고 끝내면 된다. 근데 그런줄도 모르고 그냥 dfs하다가 고생했다.
'공부 > 알고리즘' 카테고리의 다른 글
[프로그래머스 탐욕법]큰 수 만들기 - Python3 (0) | 2020.02.11 |
---|---|
[프로그래머스 탐욕법]체육복 - Python3 (0) | 2020.02.11 |
[프로그래머스 DFS/BFS]네트워크 - Python3 (0) | 2020.02.06 |
[알고리즘 자습]재귀(recursive) 함수 - N까지의 합, 거듭제곱, 구구단, 팩토리얼 등 예제- Python3 (0) | 2020.02.06 |
[프로그래머스 DFS/BFS]타겟 넘버 - Python3 (0) | 2020.02.06 |