代码改变世界

[LeetCode] 126. Word Ladder II_Hard tag: BFS&DFS

2019-05-26 05:33  Johnson_强生仔仔  阅读(376)  评论(0编辑  收藏  举报

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

  1. Only one letter can be changed at a time
  2. Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

Note:

  • Return an empty list if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.

Example 1:

Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

Output:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]

Example 2:

Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

Output: []

Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.

这个是在[LeetCode] 127. Word Ladder _Medium tag: BFS的基础上,要求求出所有的方案,所以在之前bfs的基础上,加上当时的path,然后将minLength得到之后,将超过minLength的点continue,并且已经visited过的点,再visited的时候current length应该相等。

Update 07/28/2021 多加一个visitedPath, 确保有同样path的newWord不再加入到queue里面,节约时间。

Code:

import collections
class Solution(object):
    def findLadders(self, beginWord, endWord, wordList) :
        n, wordSet, ans, chars = len(beginWord), set(wordList), [], set(c for word in wordList for c in word )
        if endWord not in wordSet: return ans
        self.bfs(beginWord, endWord, wordSet, chars, ans)
        return ans
        
    def bfs(self, beginWord, endWord, wordSet, chars, ans):
        queue, visited, minLength = collections.deque([(beginWord, 1, [beginWord])]), {}, -1
        while queue:
            word, length, path = queue.popleft()
            if word == endWord and (minLength < 0 or length == minLength):
                ans.append(path)
            elif (minLength < 0 or length < minLength):
                for newWord in self.generateNewWord(word, chars):
                    if newWord in wordSet and (newWord not in visited or length + 1 == visited[newWord]):
                        visited[newWord] = length + 1
                        queue.append((newWord, length + 1, path + [newWord]))
    
    def generateNewWord(self, word, chars):
        n, newWords = len(word), []
        for i in range(n):
            for c in chars:
                if c != word[i]:
                    newWords.append(word[:i] + c + word[i + 1:])
        return newWords

 

2) 在[LeetCode] 127. Word Ladder _Medium tag: BFS 的基础上将visited变为dictionary

import collections
class Solution(object):
    def findLadders(self, beginWord, endWord, wordList) :
        wordDic, n, ans, maxDepth = set(wordList), len(beginWord), [], 0
        if endWord not in wordDic: return []
        chars, queue, visited = set(c for word in wordDic for c in word), collections.deque([(beginWord, [beginWord])]), {beginWord: 0}
        while queue:
            word, path = queue.popleft()
            if word == endWord and (maxDepth == 0 or maxDepth == len(path)):
                ans.append(path)
                maxDepth = len(path)
            elif maxDepth == 0 or len(path) < maxDepth:
                for i in range(n):
                    for c in chars:
                        newWord = word[:i] + c + word[i + 1:]
                        if (newWord not in visited or visited[newWord] == len(path) + 1) and newWord in wordDic:
                            visited[newWord] = len(path) + 1
                            queue.append((newWord, path + [newWord]))
        return ans
    

 

Update 07/28/2021 多加一个visitedPath, 确保有同样path的newWord不再加入到queue里面,节约时间。

Code

class Solution:
    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        wordSet, chars = set(wordList), set([c for word in wordList for c in word])
        queue, visited,visitedPath = collections.deque([(beginWord, 1, [beginWord])]), {beginWord: 1}, set([tuple([beginWord])])
        minLength, ans = None, []
        while queue:
            word, dis, path = queue.popleft()
            if word == endWord and (minLength is None or dis == minLength):
                minLength = dis
                ans.append(path)
            elif (minLength is None) or (dis < minLength):
                for i in range(len(word)):
                    for char in chars:
                        if char != word[i]:
                            newWord = word[:i] + char + word[i + 1:]
                            newPath = path + [newWord]
                            if newWord in wordSet and (newWord not in visited or (dis + 1 == visited[newWord] and tuple(newPath) not in visitedPath)):
                                visited[newWord] = dis + 1
                                visitedPath.add(tuple(newPath))
                                queue.append((newWord, dis + 1, newPath))
        return ans

 

Added generate newWords function.

class Solution:
    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        chars, wordSet = set([c for word in wordList for c in word]), set(wordList)
        if endWord not in wordSet: return []
        queue, visited, visitedPath = collections.deque([(beginWord, 1, [beginWord])]), {beginWord: 1}, set([tuple([beginWord])])
        maxLen = None
        ans = []
        while queue:
            word, dis, path = queue.popleft()
            if word == endWord and (maxLen is None or dis == maxLen):
                ans.append(path)
                maxLen = dis
            elif maxLen is None or dis < maxLen:
                newWords = self.generateNewWords(word, chars)
                for newWord in newWords:
                    newPath = path + [newWord]
                    if newWord in wordSet and (newWord not in visited or (visited[newWord] == dis + 1 and tuple(newPath) not in visitedPath)):
                        visited[newWord] = dis + 1
                        visitedPath.add(tuple(newPath))
                        queue.append((newWord, dis + 1, newPath))
        return ans
        
    
    
    def generateNewWords(self, word, chars):
        newWords =  []
        for i in range(len(word)):
            for c in chars:
                if c != word[i]:
                    newWords.append(word[:i] + c + word[i + 1:])
        return newWords