Word Ladder

Given two words (start and end), and a dictionary, find all transformation sequence(s) from start to end, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

 

Note:

  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

尝试用Trie 来实现这个。

最后TLE(out of time),不过算法已经正确了。 

使用Trie,扩展性更好。 可以时时的加减dict里面的word, 也可以被多次调用。

  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],

[hit, hot, dot, lot, log, dog, cog],

[hit, hot, dot, dog, cog],

[hit, hot, dot, dog, log, cog],

[hit, hot, lot, dot, dog, cog],

[hit, hot, lot, dot, dog, log, cog],

[hit, hot, lot, log, cog],

[hit, hot, lot, log, dog, cog]]

转载于:https://www.cnblogs.com/reynold-lei/p/4395497.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值