Word Ladder II
题目描述
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
Only one letter can be changed at a time Each intermediate word must exist in the word list For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
解题方法
依然是BFS, 但是这里要找到所有的最短路径,就不能直接退出,并且也不能立刻从字典里删去用过的word, 因为这一层的其他word也有可能以它为下一个neighbour, 所以要在BFS的一层node都结束后再从字典里删去 用过的数。
并且要求能够最后重建路径,所以我们用一个hashtable来存每个word的prev是什么,这样才可以重建路径。
Solution
memory limit exceeded....
from collections import deque
from string import ascii_lowercase
class Solution(object):
def findLadders(self, beginWord, endWord, wordlist):
"""
:type beginWord: str
:type endWord: str
:type wordlist: Set[str]
:rtype: List[List[int]]
"""
if not beginWord or not endWord or not wordlist:
return
wordlist.add(endWord)
level = 1
curLevelNum = 1
nextLevelNum = 0
prevHash = {}
prevHash[beginWord] = None
queue = deque()
queue.append((beginWord, level))
wordlist.remove(beginWord)
found = False
while queue:
curWord, curLevel = queue.popleft()
curLevelNum -= 1
if curWord == endWord:
found = True
removeArr = []
ns = self.getNeighbours(curWord, wordlist)
for word in ns:
queue.append((word, curLevel + 1))
nextLevelNum += 1
removeArr.append(word)
if word in prevHash:
if curWord not in prevHash[word]:
prevHash[word].append(curWord)
else:
prevHash[word] = [curWord]
if curLevelNum == 0:
for w in removeArr:
wordlist.remove(w)
curLevelNum = nextLevelNum
nextLevelNum = 0
if found:
results = []
self.getPathes(results, beginWord, endWord, prevHash)
return results
return [[]]
def getNeighbours(self, curr, wordList):
neighbours = []
for i in range(len(curr)):
for c in ascii_lowercase:
n = curr[:i] + c + curr[i+1:]
if n in wordList and n != curr:
neighbours.append(n)
return neighbours
def getPathes(self, results, beginWord, endWord, prevHash):
queue = deque()
queue.append((endWord, [endWord]))
while queue:
cur, path = queue.popleft()
if cur == beginWord:
results.append(path[::-1])
else:
for pre in prevHash[cur]:
path.append(pre)
newPath = list(path)
queue.append((pre, newPath))
path.pop()
// another方法
def getPathes(self, results, beginWord, curr, prevHash, curList):
if curr == beginWord:
newList = list(curList)
newList.reverse()
results.append(newList)
else:
for parent in prevHash[curr]:
curList.append(parent)
self.getPathes(results, beginWord, parent, prevHash, curList)
curList.pop()
优化的可以过code
def buildpath(path, word):
if len(prevMap[word])==0:
path.append(word); currPath=path[:]
currPath.reverse(); result.append(currPath)
path.pop();
return
path.append(word)
for iter in prevMap[word]:
buildpath(path, iter)
path.pop()
result=[]
prevMap={}
length=len(start)
for i in dict:
prevMap[i]=[]
candidates=[set(),set()]; current=0; previous=1
candidates[current].add(start)
while True:
current, previous=previous, current
for i in candidates[previous]: dict.remove(i)
candidates[current].clear()
for word in candidates[previous]:
for i in range(length):
part1=word[:i]; part2=word[i+1:]
for j in 'abcdefghijklmnopqrstuvwxyz':
if word[i]!=j:
nextword=part1+j+part2
if nextword in dict:
prevMap[nextword].append(word)
candidates[current].add(nextword)
if len(candidates[current])==0: return result
if end in candidates[current]: break
buildpath([], end)
return result