Word Ladder

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence 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

For example,

Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

Note:

    • Return 0 if there is no such transformation sequence.
    • All words have the same length.
    • All words contain only lowercase alphabetic characters.

做的好费劲。。。记一下思路逐渐变化的过程吧。

想法1:想用动态规划,grid[i][j]表示set中第i个元素要变成第j个元素最小需要多少步,用了3重循环(grid[i][j] = grid[i][k]+grid[k][j]这种),不光是这3重循环,每个三重循环之后要判别矩阵中是否有元素变化,若有变化就重复做这3重循环,直到矩阵元素不变,结果就毫无疑问的超时了。。。

想法2:广度/深度优先遍历,后来发现复杂度还不如上面的做法呢。。。

想法3:看了一些网上的题解,想到了用图做,这个问题可以抽象图的最短路径问题,只不过可以简化一下,因为每一步的权重都是1,所以可以按层序遍历,后遍历到的一定比先遍历到的长度要长,所以第一次到达汇点的长度也就是最短长度。这样做还是超时。。。后来发现不是层序遍历的问题,时间好多都消耗在构造图上面了。原本的做法是用一个二维矩阵记录dict中两两之间的距离是否为1,即两个端点是否邻接,这样很耗时,后来参考别人的做法,改成在遍历时判断邻接,假设当前节点表示字符串hit,将hit中每一位换成a~z中的字符,判断新字符串是否在dict中并且还没有被遍历到,因为hashset查找的时间复杂度为O(1)。找到hit的所有邻接点的复杂度为O(26*hit的长度),这个复杂度在字符串长度较小时复杂度较高。原来找出一个顶点的邻接点的复杂度为O(n*字符串的长度),在n较大时肯定不如前面的好。然后精简了一下代码,得出代码如下:

 1 public int ladderLength(String start, String end, Set<String> dict) {
 2         dict.add(end);
 3         Queue<String> queue = new LinkedList<String>();
 4         Map<String, Integer> map = new HashMap<String, Integer>();
 5         boolean found = false;
 6         queue.add(start);
 7         map.put(start, 1);
 8         while (!queue.isEmpty()) {
 9             String now = queue.poll();
10             int level = map.get(now);
11             if (now.equals(end)) {
12                 return level;
13             }
14             dict.remove(now);
15             for (int j = 0; j < now.length(); j++) {
16                 for (int i = 0; i < 26; i++) {
17                     StringBuilder sb = new StringBuilder(now);
18                     sb.setCharAt(j, (char) ('a' + i));
19                     if (dict.contains(sb.toString())
20                             && !map.containsKey(sb.toString())) {
21                         queue.add(sb.toString());
22                         map.put(sb.toString(), level + 1);
23                     }
24                 }
25             }
26         }
27         return 0;
28     }

耗时1060ms

在得出这个代码之前,还经历了一个超时的版本,就是在层序遍历的时候,每次遍历一层,这样需要另一个queue来记录下一层的元素,代码如下:

 1 public int ladderLength(String start, String end, Set<String> dict) {
 2         dict.add(end);
 3         Queue<String> queue = new LinkedList<String>();
 4         int level = 1;
 5         boolean found = false;
 6         queue.add(start);
 7         while (!queue.isEmpty()) {
 8             Queue<String> temp = new LinkedList<String>();
 9             while (!queue.isEmpty()) {
10                 String now = queue.poll();
11                 if (now.equals(end)) {
12                     return level;
13                 }
14                 dict.remove(now);
15                 for (int j = 0; j < now.length(); j++) {
16                     for (int i = 0; i < 26; i++) {
17                         StringBuilder sb = new StringBuilder(now);
18                         sb.setCharAt(j, (char) ('a' + i));
19                         if (dict.contains(sb.toString())) {
20                             temp.add(sb.toString());
21                         }
22                     }
23                 }
24             }
25             level++;
26             queue = temp;
27         }
28         return 0;
29     }

超时的原因不是很清楚,是因为维护了另一个queue么????

posted @ 2014-07-02 14:24  秋风一片叶  阅读(245)  评论(0编辑  收藏  举报