题目描述:给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换后得到的单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
解题思路一:先利用字典里的单词以及开始和结尾单词构建一个图,如果两个单词之间只有一个字母不一样那么他们之间就会有一条边,然后通过回溯的方法找到转移的路径,构建图的过程可以用队列模拟bfs的过程,只要达到了结尾单词就可以结束循环
class Solution:
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
word_dict = set(wordList)
if endWord not in word_dict:
return []
if beginWord in word_dict:
word_dict.remove(beginWord)
from collections import defaultdict
G = defaultdict(list)
import queue
q = queue.Queue()
q.put(beginWord)
word_dict.remove(endWord)
found = False
while(q.qsize()):
tmp = set()
for j in range(q.qsize()):
curword = q.get()
for i in range(len(curword)):
for k in range(26):
tmpword = curword[:i]+chr(ord('a')+k)+curword[i+1:]
if tmpword == endWord:
G[curword].append(tmpword)
found = True
break
if tmpword in word_dict:
G[curword].append(tmpword)
if tmpword not in tmp:
q.put(tmpword)
tmp.add(tmpword)
if found: break
for word in tmp:
word_dict.remove(word)
ans = []
def traceback(src, dst, path):
if src == dst:
ans.append(path[:])
return
for word in G[src]:
path.append(word)
traceback(word, dst, path)
path.pop()
if found:
path = [beginWord]
traceback(beginWord, endWord, path)
return ans
思路二:在构建图的时候可以从头结点和尾结点同时构建,每次选择分支数更少的那一端,需要注意的是因为这里构建图的方向会发上反转,因此在找到最短路径时也不能立刻break出来,代码如下:
class Solution:
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
word_dict = set(wordList)
if endWord not in word_dict:
return []
if beginWord in word_dict:
word_dict.remove(beginWord)
from collections import defaultdict
G = defaultdict(list)
word_dict.remove(endWord)
q1 = {beginWord}
q2 = {endWord}
found = False
reverse = False
while(len(q1)):
q = set()
for word in q1:
for i in range(len(word)):
for j in range(26):
tmpword = word[:i]+chr(ord('a')+j)+word[i+1:]
if tmpword in q2:
if reverse:
G[tmpword].append(word)
else:
G[word].append(tmpword)
found = True
if tmpword in word_dict:
if reverse:
G[tmpword].append(word)
else:
G[word].append(tmpword)
q.add(tmpword)
if found: break
for word in q:
word_dict.remove(word)
if len(q) <= len(q2):
q1 = q
else:
q1 = q2
q2 = q
reverse = not reverse
ans = []
def traceback(src, dst, path):
if src == dst:
ans.append(path[:])
return
for word in G[src]:
path.append(word)
traceback(word, dst, path)
path.pop()
if found:
path = [beginWord]
traceback(beginWord, endWord, path)
return ans