Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
- Only one letter can be changed at a time
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
Note:
- Return an empty list if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: [ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ]
Example 2:
Input: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"] Output: [] Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
思路:BFS,注意保存BFS过程中的信息。
1.定义一个HashMap<String,List<String>> route 保存路径。(方向为value到key)
2.广搜每一次循环搜一层,所以代码中不用记录String和层数的映射了。
3.最后用DFS,在HashMap<String,List<String>> route 搜索路径。
4.定义mark标记已搜到的单词,在下一层不会再搜到,mark[i]==0表示还未搜到,mark[i]==1表示已搜到,但还在当前 层。mark[i]==2表示搜到,并已经到了下一层,已不会搜到。
5.因为第一版本的BFS时是遍历wordList中每个元素,再每个字符串相匹配,这样速度慢,每次匹配一个元素要O(L*m)的复杂度,L为字符串长度,m为wordList的字符串个数,AC后要600+ms。所以在第二版本中先把wordList存在一个HashMap中,在替换每个要匹配的String中的一个字符,再到HashMap中找,理论上每次匹配时间复杂度为O(26*L),AC后218ms。
第一版本:
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { HashMap<String,List<String>> route=new HashMap<>();//list to string LinkedList<String> queue=new LinkedList<>(); List<List<String>> list=new ArrayList<>(); int[] mark=new int[wordList.size()]; boolean isEnd=false;//标记已找到 queue.add(beginWord); while(!isEnd&&queue.size()!=0){ int len=queue.size(); while((len--)>0){ String str=queue.poll(); for(int i=0;i<wordList.size();i++){ if(mark[i]!=2&&connect(wordList.get(i),str)){ if(route.get(wordList.get(i))==null){ List<String> l=new ArrayList<>(); l.add(str); route.put(wordList.get(i),l); }else{ route.get(wordList.get(i)).add(str); } if(endWord.equals(wordList.get(i))){ isEnd=true;//找到就是最后一次循环 }else{ if(mark[i]!=1){//本次循环已经找到次数 queue.add(wordList.get(i)); } } mark[i]=1; } } } for(int i=0;i<mark.length;i++){ if(mark[i]==1){ mark[i]=2; } } } List<String> l=new ArrayList<>(); if(route.get(endWord)==null) return list; l.add(endWord); addString(route,list,l,endWord,beginWord); return list; } public void addString(HashMap<String,List<String>> route,List<List<String>> list,List<String> l,String word,String start){ if(start.equals(word)){ list.add(new ArrayList(l)); return; } for(String s:route.get(word)){ l.add(0,s); addString(route,list,l,s,start); l.remove(0); } } public boolean connect(String str1,String str2){ if(str1.equals(str2)||str1.length()!=str2.length()) return false; int count=0; for(int i=0;i<str1.length();i++){ if(str1.charAt(i)!=str2.charAt(i)){ count++; if(count>1){ return false; } } } return true; }
第二版本:
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { HashMap<String,List<String>> route=new HashMap<>();//list to string LinkedList<String> queue=new LinkedList<>(); List<List<String>> list=new ArrayList<>(); HashMap<String,Integer> map=new HashMap<>();//记录字符串和下标映射 for(int i=0;i<wordList.size();i++){ map.put(wordList.get(i),i); } int[] mark=new int[wordList.size()]; boolean isEnd=false;//标记已找到 queue.add(beginWord); while(!isEnd&&queue.size()!=0){ int len=queue.size(); while((len--)>0){ String str=queue.poll(); for(int i=0;i<str.length();i++){ for(char c='a';c<='z';c++){ if(str.charAt(i)!=c){ StringBuilder sb=new StringBuilder(str); sb.setCharAt(i,c); if(map.get(sb.toString())!=null){//在dict中找到了string int index=map.get(sb.toString()); if(mark[index]==2){ continue; } if(route.get(sb.toString())==null){//路径str到sb.toString() List<String> l=new ArrayList<>(); l.add(str); route.put(sb.toString(),l);//key存下一个 }else{ route.get(sb.toString()).add(str); } if(endWord.equals(sb.toString())){ isEnd=true;//找到就是最后一次循环 }else{ if(mark[index]!=1){//本次循环已经找到次数 queue.add(sb.toString()); } } mark[index]=1; } } } } } for(int i=0;i<mark.length;i++){ if(mark[i]==1){ mark[i]=2; } } } List<String> l=new ArrayList<>(); if(route.get(endWord)==null) return list; l.add(endWord); addString(route,list,l,endWord,beginWord); return list; } public void addString(HashMap<String,List<String>> route,List<List<String>> list,List<String> l,String word,String start){ if(start.equals(word)){ list.add(new ArrayList(l)); return; } for(String s:route.get(word)){ l.add(0,s); addString(route,list,l,s,start); l.remove(0); } } }