广度优先搜索算法编程题代表——单词接龙
题目描述:
字典 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。
二话不说,先看题,在题中我们不难发现这种字眼——”最短“,我们知道作为广度优先搜索算法,其最大的功能就是找最短路径,为什么?因为它是优先走离它最近的,一但满足条件,立刻停止搜索,这也就是为什么广度优先搜索为什么适合找最短路径问题了。
首先,由于一次只能变一个字母,并且转换过程中的中间单词必须是字典 wordList 中的单词,所以每次变一个字母都要和字典中的单词进行比对,这样导致了大量反复的比较,这样时间复杂度就成为了:
O(N*单词长度)
由于测试用例可能数据量相当庞大,所以极有可能超时,此时先上一个没有优化的代码:
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Queue<String>queue=new LinkedList<>();
HashSet<String>set=new HashSet<>();//防止重复遍历一个单词
boolean flag=false;
for(String x:wordList){
if(x.equals(endWord)){//有结果单词
flag=true;
}
int count=0;
for(int i=0;i<beginWord.length();++i){
if(beginWord.charAt(i)!=x.charAt(i)){
count++;
}
}
if(count==1){//存在改变一个字母的结果单词
queue.offer(x);
set.add(x);
}
}
if(!flag){//没有结果单词
return 0;
}
int end=1;
while(!queue.isEmpty()){
int len=queue.size();
while(len>0){
String y=queue.poll();
if(y.equals(endWord)){
return end+1;
}
for(String x:wordList){
int count=0;
for(int i=0;i<beginWord.length();++i){
if(y.charAt(i)!=x.charAt(i)){
count++;
}
}
if(count==1&&!set.contains(x)){
queue.offer(x);
}
}
len--;
}
end++;
}
return 0;
}
}
测试用例:
“cet” “ism” [“kid”,“tag”,“pup”,“ail”,“tun”,“woo”,“erg”,“luz”,“brr”,“gay”,“sip”,“kay”,“per”,“val”,“mes”,“ohs”,“now”,“boa”,“cet”,“pal”,“bar”,“die”,“war”,“hay”,“eco”,“pub”,“lob”,“rue”,“fry”,“lit”,“rex”,“jan”,“cot”,“bid”,“ali”,“pay”,“col”,“gum”,“ger”,“row”,“won”,“dan”,“rum”,“fad”,“tut”,“sag”,“yip”,“sui”,“ark”,“has”,“zip”,“fez”,“own”,“ump”,“dis”,“ads”,“max”,“jaw”,“out”,“btu”,“ana”,“gap”,“cry”,“led”,“abe”,“box”,“ore”,“pig”,“fie”,“toy”,“fat”,“cal”,“lie”,“noh”,“sew”,“ono”,“tam”,“flu”,“mgm”,“ply”,“awe”,“pry”,“tit”,“tie”,“yet”,“too”,“tax”,“jim”,“san”,“pan”,“map”,“ski”,“ova”,“wed”,“non”,“wac”,“nut”,“why”,“bye”,“lye”,“oct”,“old”,“fin”,“feb”,“chi”,“sap”,“owl”,“log”,“tod”,“dot”,“bow”,“fob”,“for”,“joe”,“ivy”,“fan”,“age”,“fax”,“hip”,“jib”,“mel”,“hus”,“sob”,“ifs”,“tab”,“ara”,“dab”,“jag”,“jar”,“arm”,“lot”,“tom”,“sax”,“tex”,“yum”,“pei”,“wen”,“wry”,“ire”,“irk”,“far”,“mew”,“wit”,“doe”,“gas”,“rte”,“ian”,“pot”,“ask”,“wag”,“hag”,“amy”,“nag”,“ron”,“soy”,“gin”,“don”,“tug”,“fay”,“vic”,“boo”,“nam”,“ave”,“buy”,“sop”,“but”,“orb”,“fen”,“paw”,“his”,“sub”,“bob”,“yea”,“oft”,“inn”,“rod”,“yam”,“pew”,“web”,“hod”,“hun”,“gyp”,“wei”,“wis”,“rob”,“gad”,“pie”,“mon”,“dog”,“bib”,“rub”,“ere”,“dig”,“era”,“cat”,“fox”,“bee”,“mod”,“day”,“apr”,“vie”,“nev”,“jam”,“pam”,“new”,“aye”,“ani”,“and”,“ibm”,“yap”,“can”,“pyx”,“tar”,“kin”,“fog”,“hum”,“pip”,“cup”,“dye”,“lyx”,“jog”,“nun”,“par”,“wan”,“fey”,“bus”,“oak”,“bad”,“ats”,“set”,“qom”,“vat”,“eat”,“pus”,“rev”,“axe”,“ion”,“six”,“ila”,“lao”,“mom”,“mas”,“pro”,“few”,“opt”,“poe”,“art”,“ash”,“oar”,“cap”,“lop”,“may”,“shy”,“rid”,“bat”,“sum”,“rim”,“fee”,“bmw”,“sky”,“maj”,“hue”,“thy”,“ava”,“rap”,“den”,“fla”,“auk”,“cox”,“ibo”,“hey”,“saw”,“vim”,“sec”,“ltd”,“you”,“its”,“tat”,“dew”,“eva”,“tog”,“ram”,“let”,“see”,“zit”,“maw”,“nix”,“ate”,“gig”,“rep”,“owe”,“ind”,“hog”,“eve”,“sam”,“zoo”,“any”,“dow”,“cod”,“bed”,“vet”,“ham”,“sis”,“hex”,“via”,“fir”,“nod”,“mao”,“aug”,“mum”,“hoe”,“bah”,“hal”,“keg”,“hew”,“zed”,“tow”,“gog”,“ass”,“dem”,“who”,“bet”,“gos”,“son”,“ear”,“spy”,“kit”,“boy”,“due”,“sen”,“oaf”,“mix”,“hep”,“fur”,“ada”,“bin”,“nil”,“mia”,“ewe”,“hit”,“fix”,“sad”,“rib”,“eye”,“hop”,“haw”,“wax”,“mid”,“tad”,“ken”,“wad”,“rye”,“pap”,“bog”,“gut”,“ito”,“woe”,“our”,“ado”,“sin”,“mad”,“ray”,“hon”,“roy”,“dip”,“hen”,“iva”,“lug”,“asp”,“hui”,“yak”,“bay”,“poi”,“yep”,“bun”,“try”,“lad”,“elm”,“nat”,“wyo”,“gym”,“dug”,“toe”,“dee”,“wig”,“sly”,“rip”,“geo”,“cog”,“pas”,“zen”,“odd”,“nan”,“lay”,“pod”,“fit”,“hem”,“joy”,“bum”,“rio”,“yon”,“dec”,“leg”,“put”,“sue”,“dim”,“pet”,“yaw”,“nub”,“bit”,“bur”,“sid”,“sun”,“oil”,“red”,“doc”,“moe”,“caw”,“eel”,“dix”,“cub”,“end”,“gem”,“off”,“yew”,“hug”,“pop”,“tub”,“sgt”,“lid”,“pun”,“ton”,“sol”,“din”,“yup”,“jab”,“pea”,“bug”,“gag”,“mil”,“jig”,“hub”,“low”,“did”,“tin”,“get”,“gte”,“sox”,“lei”,“mig”,“fig”,“lon”,“use”,“ban”,“flo”,“nov”,“jut”,“bag”,“mir”,“sty”,“lap”,“two”,“ins”,“con”,“ant”,“net”,“tux”,“ode”,“stu”,“mug”,“cad”,“nap”,“gun”,“fop”,“tot”,“sow”,“sal”,“sic”,“ted”,“wot”,“del”,“imp”,“cob”,“way”,“ann”,“tan”,“mci”,“job”,“wet”,“ism”,“err”,“him”,“all”,“pad”,“hah”,“hie”,“aim”,“ike”,“jed”,“ego”,“mac”,“baa”,“min”,“com”,“ill”,“was”,“cab”,“ago”,“ina”,“big”,“ilk”,“gal”,“tap”,“duh”,“ola”,“ran”,“lab”,“top”,“gob”,“hot”,“ora”,“tia”,“kip”,“han”,“met”,“hut”,“she”,“sac”,“fed”,“goo”,“tee”,“ell”,“not”,“act”,“gil”,“rut”,“ala”,“ape”,“rig”,“cid”,“god”,“duo”,“lin”,“aid”,“gel”,“awl”,“lag”,“elf”,“liz”,“ref”,“aha”,“fib”,“oho”,“tho”,“her”,“nor”,“ace”,“adz”,“fun”,“ned”,“coo”,“win”,“tao”,“coy”,“van”,“man”,“pit”,“guy”,“foe”,“hid”,“mai”,“sup”,“jay”,“hob”,“mow”,“jot”,“are”,“pol”,“arc”,“lax”,“aft”,“alb”,“len”,“air”,“pug”,“pox”,“vow”,“got”,“meg”,“zoe”,“amp”,“ale”,“bud”,“gee”,“pin”,“dun”,“pat”,“ten”,“mob”]
眼睛疼不疼!!!!!!
所以我又进行了优化:
1.不再采用顺序表查询当前单词是否在字典中,而替换成了HashSet,因为HashSet的查询时间复杂度是O(1);
2.不在每次在字典中查找当前单词变一个字母是否在字典中是否存在,因为时间复杂度在那摆着呢,所以,直接枚举改变一个字母所产生的所有结果,再联合HashSet的快速查询,可以有意想不到的效果;
下面放代码:
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Queue<String>queue=new LinkedList<>();
HashSet<String>set=new HashSet<>(wordList);//单词表
HashSet<String>visited=new HashSet<>();//防止重复查询一个单词
visited.add(beginWord);
queue.offer(beginWord);
int end=1;
while(!queue.isEmpty()){
int size=queue.size();
while(size>0){
String next=queue.poll();
char[]x=next.toCharArray();
for(int i=0;i<x.length;++i){
char xx=x[i];
for(char c='a';c<='z';++c){
if(c!=xx){
x[i]=c;
String newWord=new String(x);
if(set.contains(newWord)){
if(newWord.equals(endWord)){
return end+1;
}
if(!visited.contains(newWord)){
visited.add(newWord);
queue.offer(newWord);
}
}
}
}
x[i]=xx;
}
size--;
}
end++;
}
return 0;
}
}
运行结果:
写的不好的地方还请担待,一起努力,不妨关注,点赞一波吧。