LeetCode解题 126:Word Ladder II(BFS算法)
Problem 126: Word Ladder II [Hard]
Given two words (beginWord and endWord), and a dictionary’s word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
- Only one letter can be changed at a time
- 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
解题思路
因为题中要求最短路径,更适合使用BFS算法求解该题,在某一层搜索到endWord后即可停止搜索。
具体思路:
- 首先查找wordList中是否含有endWord,如果没有,直接返回空。
- 然后使用bfs搜索,队列prePaths存储到当前层的所有路径,依次推出每个路径进行下一层搜索:
a. 找到每个路径的最末单词lastWord;
b. 使用transform()函数返回lastWord的所有分支(即只改变一位字符就能到达的单词);
c. 遍历所有分支word:
i. 如果在之前层已经出现过( w o r d ∈ S e t < > p r e W o r d word \in Set<> preWord word∈Set<>preWord),那么可以直接剪枝,因为一定不会是最短路径;
ii. 如果word = endWord,可以把path加入最终结果,并将剩余的分支word直接剪枝,因为当前父节点已经到达了最终单词,没必要再遍历剩余分支,并且等到当前层全部遍历完后可以停止搜索;
iii. 如果没有以上情况,word加入path后把path加入队列prePaths。 - 当前层搜索结束后,如果已经出现endWord,直接停止搜索返回结果;如果没有还没搜索到endWord,继续搜索下一层。
假设从beginWord到endWord需要长度d,每个word分支为k,则时间复杂度为 O ( k d ) O(k^d) O(kd)。
运行结果:

要点:bfs、剪枝
Solution (Java)
class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> result = new ArrayList<List<String>>();
Set<String> dictionary = new HashSet<String>(wordList);
if(!dictionary.contains(endWord)) return result;
bfs(beginWord, endWord, dictionary, result);
return result;
}
private void bfs(String beginWord, String endWord, Set<String> wordList, List<List<String>> result){
Set<String> preWord = new HashSet<String>();
preWord.add(beginWord);
Queue<List<String>> prePaths = new LinkedList<List<String>>();
List<String> begin = new ArrayList<String>();
begin.add(beginWord);
prePaths.offer(begin);
boolean find = false;
while(!prePaths.isEmpty()){
Set<String> peerWord = new HashSet<String>();
int size = prePaths.size();
for(int i = 0; i < size; i++){
List<String> path = prePaths.poll();
String lastWord = path.get(path.size() - 1); // the last word of the path
List<String> branch = transform(lastWord, wordList);
for(String word : branch){
if(preWord.contains(word)) continue; // pruning
path.add(word);
prePaths.offer(new ArrayList<String>(path));
peerWord.add(word);
if(word.equals(endWord)){
find = true;
result.add(new ArrayList<String>(path));
break; // pruning
}
path.remove(path.size() - 1);
}
}
preWord.addAll(peerWord);
if(find){
break; // finish search
}
}
}
// all transformed word
private List<String> transform(String word, Set<String> wordList){
List<String> nextWord = new ArrayList<String>();
char[] s = word.toCharArray();
for(int i = 0; i < s.length; i++){
for(char c = 'a'; c <= 'z'; c++){
if(s[i] == c) continue;
char oldch = s[i];
s[i] = c;
if(wordList.contains(String.valueOf(s))){
nextWord.add(String.valueOf(s));
}
s[i] = oldch;
}
}
return nextWord;
}
}
修改过程
- 一开始直接使用List的contains()函数,会时间超限,将List<String> wordList转化为HashSet减少用时能够AC。
- transform()函数中原本使用String的子串拼接修改位置i上的字符,发现需要耗费大量时间,后将String word转换为char[] s后再修改s[i]会快一倍的时间。
- transform()函数的写法参考LeetCode题解,使用的方法为分别用a~z替换单词的每个位置,查看是否在wordList中,这种方法比wordList中的单词一一按位比较是否只差一位更快一些。
使用BFS解决LeetCode 126题:Word Ladder II
本文介绍了如何利用BFS算法解决LeetCode中的126题——从`beginWord`到`endWord`的最短变换序列,确保每次仅更改一个字母且目标单词存在于字典`wordList`中。当`endWord`不在字典中时,返回空列表。文中详细解释了解题思路,包括如何剪枝以优化搜索效率,并提供了Java实现的解决方案,重点优化了查找和字符串转换操作,以降低时间复杂度。
168万+

被折叠的 条评论
为什么被折叠?



