单词接龙II
给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
- 每次转换只能改变一个字母。
- 转换过程中的中间单词必须是字典中的单词。
说明:
- 如果不存在这样的转换序列,返回一个空列表。
- 所有单词具有相同的长度。
- 所有单词只由小写字母组成。
- 字典中不存在重复的单词。
- 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 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" 不在字典中,所以不存在符合要求的转换序列。
先BFS遍历图,找到所有到达结尾单词的最短路径,同时记录图。最后再DFS遍历图。
BFS遍历图:queue用来BFS遍历图。队列按结点的深度依次存放待处理的结点。首先存放第一层结点,弹出,根据第一层结点找到所有第二层结点放入队列;弹出第二层某个结点,根据此结点找到所有第三层结点放入队列,以此类推。
记录图:记录图中每个结点的父节点们。记录图中结点的层数(深度)。
DFS遍历记录的图得出结果。
1 class Solution{ 2 public boolean isDiffOneWord(String a,String b){ 3 int diffnum=0; 4 for(int i=0;i<a.length();i++){ 5 if(a.charAt(i)!=b.charAt(i)){ 6 diffnum++; 7 } 8 if(diffnum==2){ 9 return false; 10 } 11 } 12 if(diffnum==1){ 13 return true; 14 } 15 return false; 16 } 17 18 public List<List<String>> findLadders(String beginWord,String endWord,List<String> wordList){ 19 List<List<String>> res=new ArrayList<List<String>>(); 20 int endIndex=wordList.indexOf(endWord); 21 if(endIndex==-1){ 22 return res; 23 } 24 int beginIndex=wordList.indexOf(beginWord); 25 //若beginWord不在wordList中,则添加至wordList末尾 26 if(beginIndex==-1){ 27 wordList.add(beginWord); 28 beginIndex=wordList.size()-1; 29 } 30 //queue用来BFS遍历图。队列按节点的深度依次存放待处理的节点。首先存放第一层结点,弹出 31 //根据第一层结点找到所有第二层结点放入队列;以此类推 32 Queue<Integer> queue=new LinkedList<Integer>(); 33 queue.offer(beginIndex); 34 //fatherNodes、height用来记录图 35 //记录图中每个节点的父亲节点们 36 Map<Integer,List<Integer>> fatherNodes=new HashMap<Integer,List<Integer>>(); 37 for(int i=0;i<wordList.size();i++){ 38 fatherNodes.put(i,new ArrayList<Integer>()); 39 } 40 //记录图中节点的层数(深度) 41 int[] height=new int[wordList.size()]; 42 height[beginIndex]=1; 43 while(!queue.isEmpty()){ 44 int nowIndex=queue.poll(); 45 //若最短深度的路径已经记录完毕,退出循环 46 //height[nowIndex]>=height[endIndex]针对多个父亲点的情况 47 if(height[endIndex]!=0 && height[nowIndex]>=height[endIndex]){ 48 break; 49 } 50 for(int i=0;i<wordList.size();i++){ 51 //height[i]==0未访问过的节点,height[i]=height[nowIndex]+1多个父亲节点的情况,且一个父亲节点已经访问过该结点 52 if((height[i]==0 || height[i]==height[nowIndex]+1) && isDiffOneWord(wordList.get(nowIndex),wordList.get(i))){ 53 if(height[i]==0){ 54 queue.offer(i); 55 height[i]=height[nowIndex]+1; 56 fatherNodes.get(i).add(nowIndex); 57 }else{ 58 //height[i]=height[nowIndex]+1多个父亲节点的情况,且一个父亲节点已经访问过该结点 59 fatherNodes.get(i).add(nowIndex); 60 } 61 } 62 } 63 } 64 65 if(height[endIndex]==0){ 66 return res; 67 }else{ 68 List<String> list=new ArrayList<String>(); 69 list.add(wordList.get(endIndex)); 70 dfs(endIndex,list,res,wordList,fatherNodes,beginIndex); 71 } 72 return res; 73 } 74 75 public void dfs(int lastIndex,List<String> list,List<List<String>> res,List<String> wordList,Map<Integer,List<Integer>> fatherNodes,int beginIndex){ 76 if(lastIndex==beginIndex){ 77 List<String> newList=new ArrayList<String>(list); 78 Collections.reverse(newList); 79 res.add(newList); 80 return; 81 } 82 for(int i=0;i<fatherNodes.get(lastIndex).size();i++){ 83 int fatherIndex=fatherNodes.get(lastIndex).get(i); 84 list.add(wordList.get(fatherIndex)); 85 dfs(fatherIndex,list,res,wordList,fatherNodes,beginIndex); 86 list.remove(list.size()-1); 87 } 88 } 89 }