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么????

你可能感兴趣的:(word)