题目:
在字典(单词列表) wordList 中,从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:
序列中第一个单词是 beginWord 。
序列中最后一个单词是 endWord 。
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典 wordList 中的单词。
给定两个长度相同但内容不同的单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。
示例 :
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] 输出:5 解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
思路:
双向广度优先搜索,
代码长的话就一部分一部分写功能,慢慢优化,会好起来的
复杂度:
时间:单循环O( n )。
空间:O( n )。
代码:
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
//将字典先放入set
Set<String> notVisited = new HashSet<>(wordList);
//字典里没有结束词时,直接返回0
if(!notVisited.contains(endWord)) return 0;
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
int length =2;
set1.add(beginWord);
set2.add(endWord);
//被set2添加了
notVisited.remove(endWord);
while(!set1.isEmpty() && !set2.isEmpty()){
//为了保证双向广度优先的进行,哪个少就找哪个的节点
if(set2.size() < set1.size()){
Set<String> temp = set1;
set1 = set2;
set2 = temp;
}
//set3存放与当前访问的节点相邻的节点
Set<String> set3 = new HashSet<>();
//对set1中节点访问
for(String word: set1){
//一个单词修改一个字母可以演变出的所有单词
List<String> neighbors = getNeighbors(word);
for(String neighbor:neighbors){
//如果set2有其中一个,就可以返回长度了
if(set2.contains(neighbor)) return length;
//如果在未访问列表里就加到set3当中,未访问列表移除
if(notVisited.contains(neighbor)){
set3.add(neighbor);
notVisited.remove(neighbor);
}
}
}
//长度加一,并且将set3赋给set1
length++;
set1 = set3;
}
return 0;
}
//一个单词修改一个字母可以演变出的所有单词
private List<String> getNeighbors(String word){
List<String> neighbors = new LinkedList<>();
char[] chars = word.toCharArray();
for(int i =0;i<chars.length;++i){
char old = chars[i];
for(char ch = 'a';ch<='z';++ch){
if(old!=ch){
chars[i] = ch;
neighbors.add(new String(chars));
}
}
chars[i] =old;
}
return neighbors;
}