赞
踩
给定两个单词(beginWord和endWord)和一个字典wordList,找出所有从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" 不在字典中,所以不存在符合要求的转换序列。
解题思路
这个问题是之前问题Leetcode 127:单词接龙(最详细的解法!!!)的提高,首先不难想到一个解法,就是先通过之前问题找到最短路径step
,然后通过dfs
去找路径长度是step
并且起始位置是beginWord
终点位置是endWord
的路径即可。
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]: wordDict = collections.defaultdict(list) for word in wordList: for i in range(len(word)): tmp = word[:i] + "_" + word[i+1:] wordDict[tmp].append(word) q, visited, st = [(beginWord, 1)], set(), 0 while q: word, step = q.pop(0) if word not in visited: visited.add(word) if word == endWord: st = step break for i in range(len(word)): tmp = word[:i] + "_" + word[i+1:] for neigh in wordDict[tmp]: q.append((neigh, step + 1)) res, visited = [], set([beginWord]) def dfs(s, w, ws): if s == st - 1: if w == endWord: res.append(ws[::]) return for i in range(len(w)): tmp = w[:i] + "_" + w[i+1:] for neigh in wordDict[tmp]: if neigh not in visited: visited.add(neigh) dfs(s + 1, neigh, ws + [neigh]) visited.remove(neigh) dfs(0, beginWord, [beginWord]) return res
但是上面这种解法超时了,所以我们只能通过空间换时间,怎么做?就是在bfs
的过程中将所有的路径记录下来(到当前单词的全部最短路径)。怎么记录?通过字典,key
记录当前的单词,value
记录全部路径。怎么更新?遍历前一个单词(从前一个单词变换到当前单词)的所有路径,将当前单词插入路径结尾即可,并且将当前单词记录到字典中,已被后续使用。
class Solution: def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]: wordDict = collections.defaultdict(list) for word in wordList: for i in range(len(word)): tmp = word[:i] + "_" + word[i+1:] wordDict[tmp].append(word) q = collections.defaultdict(list) q[beginWord].append([beginWord]) visited, res = set(), [] while len(q): nq = collections.defaultdict(list) for k, v in q.items(): if k == endWord: return v if k not in visited: visited.add(k) for i in range(len(k)): tmp = k[:i] + "_" + k[i+1:] for neigh in wordDict[tmp]: nq[neigh] += [j + [neigh] for j in v]# 这里 q = nq return res
上面注释那行的代码就是最关键的操作,该操作类似于Leetcode 78:子集(最详细的解法!!!)中的第一种解法思路。
和之前一样,这个问题也可以使用双向bfs
,而且速度非常块。双向bfs
的实现稍微复杂一些,大家可以参考我的代码:
from collections import defaultdict class Solution: def findLadders(self, beginWord, endWord, wordList): wordDict, res = set(wordList), [] if endWord not in wordDict: return res s1, s2, step = defaultdict(list), defaultdict(list), 2 s1[beginWord].append([beginWord]) s2[endWord].append([endWord]) while s1: stack = defaultdict(list) wordDict -= s1.keys() for w, paths in s1.items(): for i in range(len(w)): for j in string.ascii_lowercase: tmp = w[:i] + j + w[i+1:] if tmp not in wordDict: continue if tmp in s2: if paths[0][0] == beginWord: res += [f + b[::-1] for f in paths for b in s2[tmp]] else: res += [b + f[::-1] for f in paths for b in s2[tmp]] stack[tmp] += [p + [tmp] for p in paths] if len(stack) < len(s2): s1 = stack else: s1, s2 = s2, stack step += 1 if res and step > len(res[0]): return res return res
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。