[leetcode]Word Ladder II @ Python
原題地址:http://oj.leetcode.com/problems/word-ladder-ii/
參考文獻:http://blog.csdn.net/doc_sgl/article/details/13341405
http://chaoren.is-programmer.com/
題意:給定start單詞,end單詞,以及一個dict字典。要求找出start到end的所有最短路徑,路徑上的每個單詞都要出現在dict中,且每次改變一個字母。如start="hit"; end="cog"; dict={"hot","dot","dog","lot","log"},則答案為:[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]。這是leetcode oj給的例子。我在實現的時候發現這個例子有點問題:end單詞不在dict中。實際的測試用例應該是start和end單詞都在dict中的,因為如果提前做一個刪除start或者end單詞的操作的話,就通不過了。我用正確的程序去測試oj給的這個例子也無法通過,就姑且認為start單詞和end單詞都在dict中吧,這樣寫出來的程序才能通過。
Word Ladder II這一道題還是比較難的,是leetcode oj中通過率最低的一道題。而由於我一直在用python來刷題,且一直在網上找不到用python寫的解法,自己又寫不出來,所以參考了網上的C++解法以及kitt的python程序,在此表示感謝。
解題關鍵點:1,這里的dict是python中的set()類型。
2,使用前驅單詞表prevMap,是python中的字典類型。用來記錄單詞的前驅。比如prevMap={cog:[log, dog]}表示cog的前驅是:log和dog。
3,在word ladder這道題中我們使用了隊列,在word ladder ii中也需要使用隊列,只不過在這個程序中使用了兩個set()來模擬隊列。candidates[previous]中存儲的是前面一層的單詞。如{dot,lot}為第三層單詞。在程序開始執行時,現將前面一層的單詞即candidates[previous]中的單詞在dict中刪除,再將candidates[current]清空,然后根據candidates[previous]中的單詞尋找下一層的單詞,如{dot,lot}的下一層為{dog,log},並將{dog,log}存入candidates[current]中,同時將單詞存入前驅單詞表中。下一次循環開始時,上一次循環的candidates[current]變成了candidates[previous],而上一次循環的candidates[previous]變成了candidates[current]並清空。如此反復執行,當某一次循環中的candidates[current]中出現了end單詞時,說明我們的路徑已經找出來了,工作完成了。
4,程序中使用了一個子函數buildpath來重建每一條路徑。如oj給的例子所產生的prevMap={cog:[log,dog], log:[lot], dog:[dot], dot:[hot], lot:[hot], hot:[hit]},這個prevMap可以使用DFS來重建每一條路徑。
源代碼:
class Solution: # @param start, a string # @param end, a string # @param dict, a set of string # @return a list of lists of string def findLadders(self, start, end, dict): 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