在问 · 算法题解

126. 单词接龙 II

题目描述

输入起始词 beginWord、目标词 endWord 和单词表 wordList,所有单词长度相同。

从 beginWord 开始,每一步把当前单词恰好改动一个字母,得到下一个单词。每一步得到的单词都必须在 wordList 里,而 beginWord 本身可以不在。最后一步得到的单词必须是 endWord。

找出所有步数最少的变换过程。每个过程写成从 beginWord 到 endWord 依次经过的单词列表。返回这些列表,顺序不限;若无法到达 endWord,返回 []。

示例 1
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]

解释:最短变换需要 4 步,恰好有两条:经过 dot、dog 或经过 lot、log。

示例 2
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
输出:[]

解释:cog 不在单词表中,无法到达。

数据范围

  • 1 <= beginWord.length <= 5
  • endWord.length == beginWord.length
  • 1 <= wordList.length <= 500
  • wordList[i].length == beginWord.length
  • 所有单词只含小写英文字母。
  • beginWord != endWord
  • wordList 中没有重复单词。

解题思路

分两步。第一步按层 BFS:先把当前层的单词从字典里删掉(保证只往更深的层走),再对每个单词枚举改一个字母的所有结果,在字典里的就进入下一层,并记录它的父节点(可能有多个)。一旦某层出现 endWord 就停止。第二步从 endWord 沿父节点回溯到 beginWord,把路径翻转后就是一条最短序列。

为什么正确

parents[x] 中的每个单词都在 x 的上一层,所以沿 parents 从 endWord 走回 beginWord 的任意路径长度都等于最短距离。

复杂度分析

设字典大小 N、单词长 L,BFS 为 O(N · 26 · L²);回溯与答案数量成正比。

易错点

不能在发现邻居时立刻从字典删除它,否则同层其他单词无法再把它记为子节点,会漏掉部分最短路径;应当在整层开始前统一删除。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        words = set(wordList)
        if endWord not in words:
            return []
        parents = {beginWord: []}
        layer = [beginWord]
        found = False
        while layer and not found:
            nxt = {}
            for w in layer:
                words.discard(w)
            for w in layer:
                for i in range(len(w)):
                    for c in 'abcdefghijklmnopqrstuvwxyz':
                        nw = w[:i] + c + w[i + 1:]
                        if nw in words:
                            nxt.setdefault(nw, []).append(w)
                            if nw == endWord:
                                found = True
            parents.update(nxt)
            layer = list(nxt)
        res, path = [], [endWord]

        def dfs(w):
            if w == beginWord:
                res.append(path[::-1])
                return
            for p in parents[w]:
                path.append(p)
                dfs(p)
                path.pop()

        if found:
            dfs(endWord)
        return res

载入编辑器,自己跑一遍 →

回溯 专题的其他题目

查看 回溯 全部题目 →