11.05每日一题
127. 单词接龙
题目可以看作是从起点到终点,可以采用BFS的方法来解,同时,由于终点是已知的,可以用双向BFS来进行时间优化,如果直接建图,每一个单词需要和除他之外的单词进行比较,复杂度为O(n*wordLength),但是如果把单词都放到一个hash表中,那么复杂度就可以减到O(26 * wordLength),使用BFS需要两个辅助数据结构,一个是队列,存放当前层,一个是visited集合,存放遍历过的节点,防止死循环。
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
//将数组放入hash表中
Set<String> wordSet = new HashSet<>(wordList);
if(wordSet.size() == 0 || !wordSet.contains(endWord)){
return 0;
}
wordSet.remove(beginWord);
//定义辅助数据结构
Queue<String> queue = new LinkedList<>();
Set<String> visited = new HashSet<>();
queue.add(beginWord);
visited.add(beginWord);
//BFS
int step = 1;
while(!queue.isEmpty()){
int currentSize = queue.size();
for(int i =0; i < currentSize; i++){
String currentWord = queue.poll();
if(func(currentWord, endWord, queue, visited, wordSet)){
return step + 1;
}
}
step++;
}
return 0;
}
boolean func(String currentWord, String endWord, Queue<String> queue, Set<String> visited, Set<String> wordSet){
char[] charArray = currentWord.toCharArray();
for(int i =0 ;i < endWord.length(); i++){
char originChar = charArray[i];
for(char k = 'a'; k <= 'z'; k++){
if(k == originChar){
continue;
}
charArray[i] = k;
String nextWord = String.valueOf(charArray);
if(wordSet.contains(nextWord)){
if(nextWord.equals(endWord)){
return true;
}
if(!visited.contains(nextWord)){
queue.add(nextWord);
visited.add(nextWord);
}
}
}
charArray[i] = originChar;
}
return false;
}
}
测试上面的代码,发现需要80多ms,还是挺慢的,使用双向BFS优化可以大量的减少使用时间,每次BFS从较短的一方开始。
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
//将数组放入hash表中
Set<String> wordSet = new HashSet<>(wordList);
if(wordSet.size() == 0 || !wordSet.contains(endWord)){
return 0;
}
//构建辅助数据结构
Set<String> visited = new HashSet<>();
visited.add(beginWord);
visited.add(endWord);
Set<String> beginVisited = new HashSet<>();
beginVisited.add(beginWord);
Set<String> endVisited = new HashSet<>();
endVisited.add(endWord);
//双向BFS
int step = 1;
while(!beginVisited.isEmpty() && !endVisited.isEmpty()){
if(beginVisited.size() > endVisited.size()){
Set<String> tmp = beginVisited;
beginVisited = endVisited;
endVisited = tmp;
}
Set<String> nextLevelVisited = new HashSet<>();
for(String word : beginVisited){
if(func(word, endVisited, visited, wordSet, nextLevelVisited)){
return step + 1;
}
}
beginVisited = nextLevelVisited;
step++;
}
return 0;
}
boolean func(String word, Set<String> endVisited, Set<String> visited, Set<String> wordSet, Set<String> nextLevelVisited){
char[] charArray = word.toCharString();
for(int i = 0; i < word.length(); i++){
char originChar = charArray[i];
for(char c = 'a'; c <= 'z'; c++){
if(originChar == c){
continue;
}
charArray[i] = c;
String nextWord = String.valueOf(charArray);
if(wordSet.contains(nextWord)){
if(endVisited.contains(nextWord)){
return true;
}
if(!visited.contains(nextWord)){
nextLevelVisited.add(nextWord);
visited.add(nextLevelVisited);
}
}
}
charArray[i] = originChar;
}
return false;
}
}
速度可以提高很多。