두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.
예를 들어 begin이 "hit", target가 "cog", words가 ["hot","dot","dog","lot","log","cog"]라면 "hit" -> "hot" -> "dot" -> "dog" -> "cog"와 같이 4단계를 거쳐 변환할 수 있습니다.
두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.
| begin | target | words | return |
|---|---|---|---|
| "hit" | "cog" | ["hot", "dot", "dog", "lot", "log", "cog"] | 4 |
| "hit" | "cog" | ["hot", "dot", "dog", "lot", "log"] | 0 |
예제 #1
문제에 나온 예와 같습니다.
예제 #2
target인 "cog"는 words 안에 없기 때문에 변환할 수 없습니다.
words에서 target 단어의 존재 여부를 확인하면 백트래킹이 가능할 것 같다.func checkSimilar(word1 string, word string) bool {
var cnt int
for i := 0; i < len(word1); i++ {
if word1[i] != word[i] {
cnt++
}
}
if cnt == 1 {
return true
}
return false
}
func solution(begin string, target string, words []string) int {
visited := map[string]int{}
q := []string{}
for _, word := range words {
visited[word] = 0
if checkSimilar(begin, word) {
q = append(q, word)
visited[word]++
}
}
_, exists := visited[target]
if !exists {
return 0
}
Loop1:
for len(q) != 0 {
now := q[0]
q = q[1:]
for _, word := range words {
if visited[word] == 0 && checkSimilar(now, word) {
visited[word] = visited[now] + 1
q = append(q, word)
if visited[target] != 0 {
break Loop1
}
}
}
}
return visited[target]
}
테스트 1 〉 통과 (0.00ms, 4.13MB)
테스트 2 〉 통과 (0.01ms, 3.54MB)
테스트 3 〉 통과 (0.02ms, 4.17MB)
테스트 4 〉 통과 (0.00ms, 3.83MB)
테스트 5 〉 통과 (0.00ms, 4.12MB)
visited에 변경 이력을 체크한다.target 단어가 words 에 있는지 쉽게 확인하기 위함이다.visited의 값을 단순한 방문 여부 뿐만 아니라 변경 회차로도 사용한다.checkSimilar() 라는 함수를 만들어 두 단어의 유사 여부를 확인한다.target 단어를 만나면 Loop를 탈출한다.func checkSimilar(word1 string, word string) bool {
var cnt int
for i := 0; i < len(word1); i++ {
if word1[i] != word[i] {
cnt++
}
}
if cnt == 1 {
return true
}
return false
}
func dfs(now, target string, words []string, visited []int, cnt int, min_cnt *int) {
if cnt >= *min_cnt {
return
}
if now == target {
if cnt < *min_cnt {
*min_cnt = cnt
}
return
}
for idx, word := range words {
if visited[idx] == 0 && checkSimilar(now, word) {
visited[idx] = 1
dfs(word, target, words, visited, cnt+1, min_cnt)
visited[idx] = 0
}
}
return
}
func solution(begin string, target string, words []string) int {
min_cnt := len(words) + 1
visited := make([]int, len(words))
dfs(begin, target, words, visited, 0, &min_cnt)
if min_cnt == len(words) + 1 {
return 0
}
return min_cnt
}
테스트 1 〉 통과 (0.00ms, 3.57MB)
테스트 2 〉 통과 (0.00ms, 4.19MB)
테스트 3 〉 통과 (0.01ms, 4.19MB)
테스트 4 〉 통과 (0.00ms, 3.55MB)
테스트 5 〉 통과 (0.00ms, 4.27MB)
visited를 생성한다. 이번에는 Map이 아니라 Array를 사용했다.begin 단어를 시작으로 DFS를 돌린다. 이때 파라미터로는 현재단어, 타겟단어, 단어목록, 확인이력, 변경횟수, 최소변경횟수를 사용하는데 DFS 함수의 스코프 밖에서 선언한 min_cnt의 값을 함수 내에서 변경하기 위해 포인터를 사용했다.def similar(w1, w2):
cnt = 0
for i in range(len(w1)):
if w1[i] != w2[i]:
cnt += 1
return True if cnt == 1 else False
def solution(begin, target, words):
visited = {w: 0 for w in words}
if visited.get(target) is None:
return 0
q = []
for word in words:
if similar(begin, word):
q.append(word)
visited[word] += 1
while len(q) != 0:
now = q.pop(0)
if now == target:
break
for word in words:
if similar(now, word) and visited[word] == 0:
visited[word] = visited[now] + 1
q.append(word)
return visited[target]
테스트 1 〉 통과 (0.01ms, 10.1MB)
테스트 2 〉 통과 (0.09ms, 10.3MB)
테스트 3 〉 통과 (0.69ms, 10.1MB)
테스트 4 〉 통과 (0.01ms, 10.2MB)
테스트 5 〉 통과 (0.00ms, 10MB)
def similar(w1, w2):
cnt = 0
for i in range(len(w1)):
if w1[i] != w2[i]:
cnt += 1
return True if cnt == 1 else False
def solution(begin, target, words):
def dfs(now, cnt):
nonlocal target, words, visited, min_cnt
if cnt >= min_cnt:
return
if now == target:
min_cnt = min(cnt, min_cnt)
return
for word in words:
if visited[word] == 0 and similar(now, word):
visited[word] = 1
dfs(word, cnt+1)
visited[word] = 0
return
min_cnt = 51
visited = {w: 0 for w in words}
if visited.get(target) is None:
return 0
dfs(begin, 0)
if min_cnt == 51:
return 0
return min_cnt
테스트 1 〉 통과 (0.01ms, 10.2MB)
테스트 2 〉 통과 (0.13ms, 10.2MB)
테스트 3 〉 통과 (0.66ms, 10.3MB)
테스트 4 〉 통과 (0.01ms, 10MB)
테스트 5 〉 통과 (0.00ms, 10.2MB)