题目
给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
输出:
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
示例 2:
输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
输出: []
解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。
示例:
输入:
"red"
"tax"
["ted","tex","red","tax","tad","den","rex","pee"]
输出:[["red","ted","tad","tax"],["red","ted","tex","tax"],["red","rex","tex","tax"]]
【困难】
【分析1】
用一个很暴力的方法写出来了(一层一层往下遍历得到到end的所有序列,然后选出最小长度序列,emmmmm 自然是超时了……)
from collections import defaultdict
class Solution:
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
if endWord not in wordList or not beginWord or not endWord or not wordList:
return []
#预处理
dic=defaultdict(list)
L=len(wordList[0])
for word in wordList:
if word!=beginWord:
for i in range(L):
dic[word[0:i]+"*"+word[i+1::]].append(word)
queue=[beginWord]
seen=defaultdict(list)
seen[beginWord]=[[beginWord]] #记录已经访问过的单词,并记录在访问该单词之前已经访问过的单词
while queue:
word=queue.pop(0)
next_word=set()
for i in range(L):
for w in dic[word[0:i]+"*"+word[i+1::]]:
if w!=word:
next_word.add(w)
next_word
if endWord in next_word:
if endWord not in seen:
for lastwords in seen[word]:
seen[endWord]=[lastwords+[endWord]]
else:
for lastwords in seen[word]:
if lastwords+[endWord] not in seen[endWord]:
seen[endWord].append(lastwords+[endWord])
else:
for w in next_word:
if w not in seen:
for lastwords in seen[word]:
seen[w]=[lastwords+[w]]
queue.append(w)
else:
for lastwords in seen[word]:
if w not in lastwords and lastwords+[w] not in seen[w]:
seen[w].append(lastwords+[w])
queue.append(w)
if len(seen[endWord])==0:
return []
else:
ans=[]
min_=len(min(seen[endWord]))
for w in seen[endWord]:
if len(w)==min_:
ans.append(w)
return ans
【分析2】先利用BFS从endWord到beginWord得到满足连通要求的单词到endWord的最短距离dist。
再利用DFS遍历从beginWord到endWord的得到满足dist的所有单词序列。(注:这里DFS利用递归来做,不能用栈,因为要得到所有满足要求的单词序列)
老实讲,对wordList处理这一块,一开始我是用的List把beginWord加进去,但是运行却是超时的;后来改成把wordList改成set了时间上刚好满足要求(无语到一口老血都喷出来了。。。)。
class Solution:
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
wordList=set(wordList)
wordList.add(beginWord)
#wordList.append(beginWord)
dist=self.bfs(endWord,wordList)
res=[]
self.dfs(beginWord,endWord,wordList,dist,[beginWord],res)
return res
#bfs记录点到终点的最短距离:end -> start
def bfs(self,begin,wordList):
dist={}
dist[begin]=0
queue=[begin]
while queue:
L=len(queue)
for _ in range(L):
word=queue.pop(0)
for w in self.nextWord(word,wordList):
if w not in dist:
dist[w]=dist[word]+1
queue.append(w)
return dist
#利用递归来记录路径:从start -> end
def dfs(self,curr,end,wordList,dist,path,res):
if curr==end:
res.append(list(path))
for w in self.nextWord(curr,wordList):
if dist[w]==dist[curr]-1:
path.append(w)
self.dfs(w,end,wordList,dist,path,res)
path.pop()
def nextWord(self,word,wordList):
res=[]
for i in range(len(word)):
for letter in "abcdefghijklmnopqrstuvwxyz":
next_=word[0:i]+letter+word[i+1::]
if next_!=word and next_ in wordList:
res.append(next_)
return res
【注】py中set可以有操作set.discard(value),set.add(value).
使用b=a.copy().
最后感谢一下刷过这道题的大佬,真的nice啊,参考了你的我才做出来。。。。。哎,加油吧皮卡丘。