Given two words (start and end), and a dictionary, find all transformation sequence(s) from start to end, such that:java
Note:node
嘗試用Trie 來實現這個。面試
最後TLE(out of time),不過算法已經正確了。 算法
使用Trie,擴展性更好。 能夠時時的加減dict裏面的word, 也能夠被屢次調用。app
1 package leetcode; 2 3 import java.util.ArrayList; 4 import java.util.HashSet; 5 import java.util.Iterator; 6 import java.util.List; 7 import java.util.Set; 8 9 //implement wordLadder with Trie. 10 /* 11 * 若是這個函數要屢次被調用,怎麼辦? 12 * 由於我每次都用挨個修改字母的辦法來尋找新word,但若是能先對dictionary作個預處理,弄個從word到set of words之間的mapping,那麼每輪BFS就能夠省去尋找新詞的時間。預處理字典的複雜度也是O(size of dictionary) * (length of string) * 26。最終能夠用一個Hash<String, Set<String>>來表示這個mapping關係。 13 * 14 * 若是這個字典要增長/移除單詞怎麼辦? 15 * 增長的話,只須要對新單詞作一樣的事情:修改每一個字母找下一個單詞,而後那個被找到下一個單詞的mapping裏同時也添加進新單詞。由於這個關係是可互換的,若是wordA => wordB, 那麼wordB => wordA。 16 * 刪除的時候同理,對於map.get(toBeRemoved)裏的全部單詞的mapping集合都刪掉這個toBeRemoved,而後再從map裏面去掉它本身,寫出來的代碼大概是這樣: 17 * for (String s : map.get(toBeRemoved)) map.get(s).remove(toBeRemoved); 18 * map.remove(toBeRemoved); 19 * 這個地方我一開始沒注意到能夠互換,覺得還得預處理一個反方向的mapping,通過面試官兩次提醒才發現了這個規律…… 20 * 21 * 若是這個字典變得很龐大,這個mapping和字典自己就太佔空間了,怎麼處理? 22 * 用trie記錄全部單詞,每一個node用一個bit記錄這個node是否爲一個單詞,而且有一個set<myTrieNode>的field記錄他能夠變成的其餘單詞。至於如何構建這個field,利用trie的特性,能夠用回溯的方法很是簡單地找到可變過去的單詞(在碰到公共ancestor以前,路徑上的node個數必須相同,這個用於保證長度,而且至多隻有一個字母不一樣,用於知足mapping的條件) 23 * 至此……時間終於用完了,問了下他的team的狀況,就結束了…… 24 * 25 * */ 26 27 class myTrieNode{ 28 Boolean isWord; 29 myTrieNode[] childList; 30 Integer freq; 31 char val; 32 String word; 33 34 public myTrieNode(){//use to generate root of Trie 35 this.freq = 0; 36 this.childList = new myTrieNode[26]; 37 this.isWord = false; 38 } 39 40 public myTrieNode(char c){ 41 this.val = c; 42 this.freq = 1; 43 this.childList = new myTrieNode[26]; 44 } 45 46 public String containsWord(String s){ 47 if(s == null || s.length() == 0){ 48 if(this.word != null && this.isWord == true) return this.word; 49 else return ""; 50 } 51 int len = s.length(); 52 myTrieNode cur = this; 53 for(int i = 0; i < len; i ++){ 54 char c = s.charAt(i); 55 if(cur.childList[c - 'a'] != null){ 56 cur = cur.childList[c - 'a']; 57 }else{ 58 return null; 59 } 60 } 61 return cur.isWord == true ? cur.word : null; 62 } 63 } 64 class myTrie{ 65 myTrieNode root; 66 67 public myTrie(){ 68 this.root = new myTrieNode(); 69 } 70 71 public void insert(String word){ 72 if(word == null || word.length() == 0) return; 73 int len = word.length(); 74 myTrieNode cur = this.root; 75 for(int i = 0; i < len; i ++){ 76 char c = word.charAt(i); 77 if(cur.childList[c - 'a'] == null){ 78 cur.childList[c - 'a'] = new myTrieNode(c); 79 }else{ 80 cur.childList[c - 'a'].freq ++; 81 } 82 cur = cur.childList[c - 'a']; 83 if(i == word.length() - 1){ 84 cur.isWord = true; 85 cur.word = word; 86 } 87 } 88 } 89 90 } 91 public class WordLadder { 92 93 94 private static myTrie trie; 95 private static List<List<String>> result; 96 public static List<List<String>> findLadders(String start, String end, Set<String> dict) { 97 trie = generateTrie(dict); 98 trie.insert(end); 99 result = new ArrayList<List<String>> (); 100 ArrayList<String> row = new ArrayList<String>(); 101 row.add(start); 102 findLadderSequence(start, end, row, new HashSet<String>()); 103 return result; 104 } 105 106 private static void findLadderSequence(String start, String end, ArrayList<String> row, HashSet<String> usedSet){ 107 if(start.equals(end)){ 108 result.add(row); 109 } 110 myTrieNode cur = trie.root; 111 myTrieNode next = cur; 112 for(int i = 0; i < start.length(); i ++){ 113 char c = start.charAt(i); 114 for(int j = 0; j < 26; j ++){ 115 if(cur.childList[j] != null && cur.childList[j].val == c){ 116 next = cur.childList[j]; 117 } 118 if(cur.childList[j] != null && cur.childList[j].val != c){ 119 String tmp = cur.childList[j].containsWord(start.substring(i + 1)); 120 if(tmp != null && !usedSet.contains(tmp)){ 121 row.add(tmp); 122 usedSet.add(tmp); 123 findLadderSequence(tmp, end, new ArrayList<String>(row), new HashSet<String>(usedSet)); 124 row.remove(row.size() - 1); 125 usedSet.remove(tmp); 126 } 127 } 128 } 129 cur = next; 130 } 131 132 } 133 134 private static myTrie generateTrie(Set<String> dict){ 135 myTrie trie = new myTrie(); 136 if(dict.isEmpty()) return trie; 137 //generate Trie for dictionary 138 Iterator it = dict.iterator(); 139 while(it.hasNext()){ 140 String word = (String)it.next(); 141 trie.insert(word); 142 } 143 return trie; 144 } 145 146 public static void main(String[] args){ 147 String start = "hit"; 148 String end = "cog"; 149 Set<String> dict = new HashSet<String>(); 150 dict.add("hot"); 151 dict.add("dot"); 152 dict.add("dog"); 153 dict.add("lot"); 154 dict.add("log"); 155 findLadders(start, end, dict); 156 System.out.println(result); 157 } 158 }
Output:函數
[[hit, hot, dot, lot, log, cog],this
[hit, hot, dot, lot, log, dog, cog],spa
[hit, hot, dot, dog, cog],code
[hit, hot, dot, dog, log, cog],orm
[hit, hot, lot, dot, dog, cog],
[hit, hot, lot, dot, dog, log, cog],
[hit, hot, lot, log, cog],
[hit, hot, lot, log, dog, cog]]