单词接龙
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
输出: 5
解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
返回它的长度 5。
示例 2:
输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
输出: 0
解释: endWord "cog" 不在字典中,所以无法进行转换。
方法1: DFS
- 使用队列广度搜索,时间复杂度为O(n^2*L)
import java.util.*;
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Queue<String> queue = new LinkedList<String>();
boolean[] path = new boolean[wordList.size()];
String temp;
int len = 0;
queue.add(beginWord);
while(!queue.isEmpty()){
int size = queue.size();
while(size -- >0){
temp = queue.remove();
if(temp.equals(endWord)) return len+1;
for(int i = 0 ;i<wordList.size();i++){
String p = wordList.get(i);
if(isEquals(temp,p) && path[i]==false){
path[i] = true;
queue.add(p);
}
}
}
len++;
}
return 0;
}
public boolean isEquals(String x, String y){
int count = 0;
for(int i = 0;i<y.length();i++){
if(x.charAt(i) != y.charAt(i)){
count ++;
}
if(count>1) break;
}
return count <= 1;
}
}
方法2:双向DFS
- 使用双向DFS,从头尾两个方向向中间搜索,当两端搜索的集合包含重叠元素时,表示两端可以在该点连同。
- 当第一次听说双向DFS,以为使用两个队列,但判断是否包含重叠元素时队列不好判断,所以使用Set容器比较方便。set每次保存搜索到的一层元素。
- 对于头尾集合,保证每次都是从元素最少的集合中开始向下一层搜索,减少搜索时间。
- 时间复杂度:每个元素都要放入set遍历一次,对于每个单词的每一位,都要用a-z替换一次,判断替换后的单词是否存在在另一个set中,hashset查询复杂度O(L),所以总的时间复杂度为 n26L^2
算法流程:
- 构建头尾两个集合,保证头集合为元素最少的集合
- 从头集合开始搜索,当搜索到的元素在尾集合时,则说明已经到达,结束搜索
- 否则 将搜索到的元素放入新的头集合中,进行下一层搜索。
import java.util.*;
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> wordSet = new HashSet<>(wordList);
Set<String> startSet = new HashSet<>();
Set<String> endSet = new HashSet<>();
startSet.add(beginWord);
endSet.add(endWord);
int len = 1;
char[] ch;
Set<String> temp;
if(!wordSet.contains(endWord)) return 0;
while(!startSet.isEmpty() && !endSet.isEmpty()){
len ++;
if(startSet.size() > endSet.size() ){
temp = endSet;
endSet = startSet;
startSet = temp;
}
// System.out.print(startSet.toString());
// System.out.println(endSet.toString());
Set<String> newhead = new HashSet<>();
for(String p : startSet){
ch = p.toCharArray();
for(int i = 0;i < p.length();i++){
char k = ch[i];
for(char c = 'a';c <='z';c++){
if(c == k) continue;
ch[i] = c;
String res = String.valueOf(ch);
// System.out.println(res);
if(endSet.contains(res))
return len;
if(wordSet.contains(res)){
// System.out.println(res);
wordSet.remove(res);
newhead.add(res);
}
}
ch[i] = k;
}
}
startSet = newhead;
}
return 0;
}
}