LC127 · 单词接龙 · 工程执行实验室
隐形图上的 BFS 扩散
单词列表是一张隐形无权图:结点 = 单词,边 = 只差一个字母。BFS 按层从 beginWord 扩散,第一次到达 endWord 的层数就是最短序列长度(含起点)。
核心机制 · 隐形图 + BFS
单词列表是一张隐形无权图:结点=单词,边=只差一个字母;BFS 按层扩散,第一次到达 endWord 的层数就是最短序列长度。
- · 结点 = 单词;边 = 只差一个字母(无权,代价 1)。
- · BFS 按层扩散,level 从 beginWord 算起 = 序列长度。
- · size := len(queue) 冻结当前层;visited 入队时标记。
hit - hot - dot - dog - cog
| |
lot - log ----最短路径 hit→hot→dot→dog→cog,5 个单词,返回 5。
BFS 在无权图上按距离从近到远扩展。queue 中同一层的单词连续排列;每层开始用 size := len(queue) 冻结,只处理本层。visited 在入队时标记,保证每个单词最多入队一次。第一次出队 endWord 时,level 即为最短序列长度。
读题:单词列表如何变成最短变换序列?
beginWord="hit",endWord="cog",wordList=[hot,dot,dog,lot,log,cog]。每次只能改一个字母,且中间词必须在 wordList 中。求最短序列长度。
单词列表是一张隐形无权图:结点=单词,边=只差一个字母;BFS 按层扩散,第一次到达 endWord 的层数就是最短序列长度。
关键不是背 BFS 模板,而是先看见「单词列表 = 一张隐形图」。
状态表 · queue / level / visited
尚未开始 BFS
BFS 队列执行表
单词图 · BFS 层级扩散
1func ladderLength(beginWord, endWord string, wordList []string) int {2 wordSet := make(map[string]bool)3 for _, w := range wordList {4 wordSet[w] = true5 }6 if !wordSet[endWord] {7 return 08 }9 queue := []string{beginWord}10 visited := map[string]bool{beginWord: true}11 level := 112 for len(queue) > 0 {13 size := len(queue)14 for i := 0; i < size; i++ {15 word := queue[0]16 queue = queue[1:]17 if word == endWord {18 return level19 }20 for j := 0; j < len(word); j++ {21 for c := 'a'; c <= 'z'; c++ {22 next := word[:j] + string(c) + word[j+1:]23 if !wordSet[next] || visited[next] {24 continue25 }26 visited[next] = true27 queue = append(queue, next)28 }29 }30 }31 level++32 }33 return 034}
wordSet 用于 O(1) 判断单词是否存在
endWord 不在 wordList 时直接返回 0
queue 初始化为 beginWord,level 从 1 起
size := len(queue) 冻结当前 BFS 层
出队队首 word,准备扩展邻居
出队时若已是 endWord,返回到达层数
逐位尝试 a-z 生成 next
next 必须在 wordSet 且未 visited
入队时标记 visited,避免重复入队
整层处理完才 level++
- · 这是一张无权图:每条边代表「改一个字母」,代价相同。
- · BFS 按距离从近到远搜索,先处理的层一定更近。
- · 第一次到达 endWord 时,路径上的单词数(含起点)就是最短序列长度。
- 朴素变字母 BFS
- 时间 O(N · L²) · 空间 O(N)
- 通配符建桶
- 时间 O(N · L²) · 空间 O(N · L)
N = 单词数量,L = 单词长度。朴素变字母 BFS 每个词尝试 L×26 种变换;通配符建桶额外存 L 个桶。
把 wordList 放进 wordSet;若 endWord 不在集合里直接返回 0。beginWord 入队,level=1,visited 入队时标记。每层 size:=len(queue) 固定当前层,逐词出队,对每个位置尝试 a-z 生成 next;next 在 wordSet 且未访问则入队并标记 visited。出队词等于 endWord 时返回 level。朴素变字母:时间 O(N·L²),空间 O(N);通配符建桶:时间 O(N·L²),空间 O(N·L)。
hit→hot→dot→dog→cog 共 5 个单词;题目要的是序列长度,不是边数。
endWord 不在 wordSet 时无法到达,应直接返回 0,否则 BFS 白跑。
同一单词可能被多个邻居重复加入 queue,层数和队列都会膨胀。应在入队时立刻标记。
O(N²·L) 两两比较在大列表会 TLE;应改字母查 wordSet 或通配符桶。
level++ 应放在内层 for 结束后(整层处理完再加),不能每出队一个词就加。