给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
题解:
1.两个单词、一个字典
2.从 beginWord 到 endWord 的最短转换序列,不存在返回空
3.每次转换只能改变一个字母
4.转换的中间单词在字典中
示例 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" 不在字典中,所以不存在符合要求的转换序列。
解题思路:
先把开始单词和目标单词添加到容器中方便处理
对每次查找转换序列,建立一个“链表”(用map映射),map里的key和value值分别对应前一个单词和转换的后一个单词
递归上一个过程,如果在最后在字典里找到了这个目标单词,说明存在一条可达路径
直到存在后,递归搜索这个单词路径,中间单词都记录下来作为返回
如果判断不存在这个路径,直接返回空列表
Java题解:
class Solution {
public List> findLadders(String beginWord, String endWord, List
List> res = new ArrayList<>();//返回一个二维列表
Set
if (!words.contains(endWord)) {
return res;}// 字典中没有目标单词,不能转换
// 存放关系:每个单词可达的下层单词
Map
Set
begin.add(beginWord); //字符输入加到容器里
end.add(endWord); //目标字符加到容器里
if (buildTree(words, begin, end, mapTree, true)) {//如果有一条可达路径
//递归把中间单词加到结果里
dfs(res, mapTree, beginWord, endWord, new LinkedList<>());}
return res;}
// 双向BFS,构建每个单词的层级对应关系
private boolean buildTree(Set
if (begin.size() == 0) {
return false; }
// 始终以少的进行探索
if (begin.size() > end.size()) {
return buildTree(words, end, begin, mapTree, !isFront); }
// 在已访问的单词集合中去除
words.removeAll(begin);
// 标记本层是否已到达目标单词
boolean isMeet = false;
// 记录本层所访问的单词
Set
for (String word : begin) {
char[] chars = word.toCharArray();
for (int i = 0; i < chars.length; i++) {
char temp = chars[i];
for (char ch = 'a'; ch <= 'z'; ch++) {
chars[i] = ch;//尝试替换每个字母
String str = String.valueOf(chars); //替换完转成String
if (words.contains(str)) { //如果字典中有替换完的单词
nextLevel.add(str); //把中间单词记录下来
// 根据访问顺序,添加层级对应关系:始终保持从上层到下层的存储关系
// true: 从上往下探索:word -> str
// false: 从下往上探索:str -> word(查找到的 str 是 word 上层的单词)
String key = isFront ? word : str;
String nextWord = isFront ? str : word;
// 判断是否遇见目标单词
if (end.contains(str)) {//end里是目标单词
isMeet = true; }//如果当前中间过程单词是目标单词,停止
if (!mapTree.containsKey(key)) {//存储关系,没有key就添加
mapTree.put(key, new ArrayList<>());}
//添加key对应的value值,key上一个中间单词,value为下一个单词
mapTree.get(key).add(nextWord);}}
chars[i] = temp; } }//找到中间过程单词,把开始单词还原
if (isMeet) {//到达目标单词,则有一条路径从开始单词到达目标单词
return true; }//返回true
return buildTree(words, nextLevel, end, mapTree, isFront);}
// DFS: 组合路径
private void dfs (List> res, Map
list.add(beginWord);
if (beginWord.equals(endWord)) {//开始单词和目标单词相同
res.add(new ArrayList<>(list));}//返回该单词
//map中key和value分别对应前后单词
if (mapTree.containsKey(beginWord)) {//map中有开始单词的key
for (String word : mapTree.get(beginWord)) {//递归把value里的中间单词
dfs(res, mapTree, word, endWord, list); }}//添加到结果集里
list.removeLast();}}
Debug结果:
更多题解移步公众号免费获取