题目大意:给出一个字符串列表list,一个源字符串,一个目标字符串,且这些字符串拥有相同长度。要求每次最多变换源字符串中一个字符,且每次变换的结果都应该在list中有相同的字符串。求所有从源字符串到目标字符串变换次数最少的策略。
相当简单的题目,可以将每个字符串看作一个顶点,而若两个字符串之间只有一个字符不同,那么就认为这两个字符串之间有双向边。这样就构建了一幅图,之后从源字符串对应的顶点出发,去寻找到达目标字符串的方案,就相当于找从源顶点出发到目标顶点的最短路径。这个过程利用广度优先搜索即可实现,搜索的时间复杂度最多为O(V)+O(E)<=O(V^2)。
时间复杂度是非多项式的,因为题目还要求给出所有最短的路径。这样可能的总共的路径数目可以达到O(2^n)级别。因此其实这道题目并不好,之所以能通过也只是因为数据不够变态。
1 package cn.dalt.leetcode; 2 3 import java.util.*; 4 5 /** 6 * Created by Administrator on 2017/9/8. 7 */ 8 public class WordLadderII { 9 public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { 10 if (beginWord.equals(endWord)) { 11 return Arrays.asList(Arrays.asList(beginWord)); 12 } 13 14 boolean pass = false; 15 for (String word : wordList) { 16 if (word.equals(endWord)) { 17 pass = true; 18 break; 19 } 20 } 21 if (!pass) { 22 return Collections.emptyList(); 23 } 24 25 int n = wordList.size(); 26 int m = beginWord.length(); 27 28 Node[] node = new Node[n + 2]; 29 for (int i = 0, bound = wordList.size(); i < bound; i++) { 30 node[i] = new Node(); 31 node[i].signature = wordList.get(i); 32 node[i].flag = Integer.MAX_VALUE; 33 } 34 35 node[n] = new Node(); 36 node[n].signature = beginWord; 37 node[n + 1] = new Node(); 38 node[n + 1].signature = endWord; 39 Node src = node[n]; 40 Node dst = node[n + 1]; 41 src.flag = 0; 42 dst.flag = Integer.MAX_VALUE; 43 44 //Build graph 45 for (int i = 0, bound = n + 2; i < bound; i++) { 46 for (int j = i + 1; j < bound; j++) { 47 if (differForOneLetter(node[i].signature, node[j].signature)) { 48 node[i].nearTo.add(node[j]); 49 node[j].nearTo.add(node[i]); 50 } 51 } 52 } 53 54 //BFS 55 Deque<Node> queue = new LinkedList<>(); 56 queue.add(src); 57 while (!queue.isEmpty()) { 58 Node front = queue.pollFirst(); 59 int nextFlag = front.flag + 1; 60 for (Node near : front.nearTo) { 61 if (near.flag == nextFlag) { 62 near.parent.add(front); 63 } else if (near.flag > nextFlag) { 64 near.flag = nextFlag; 65 near.parent.add(front); 66 queue.addLast(near); 67 } 68 } 69 } 70 71 List<List<String>> result = new LinkedList<>(); 72 if (dst.flag == Integer.MAX_VALUE) { 73 return Collections.emptyList(); 74 } 75 dfs(new String[dst.flag + 1], dst.flag, dst, result); 76 return result; 77 } 78 79 public void dfs(String[] route, int index, Node current, List<List<String>> routes) { 80 route[index] = current.signature; 81 if (index == 0) { 82 routes.add(Arrays.asList(route.clone())); 83 return; 84 } 85 for (Node parent : current.parent) { 86 dfs(route, index - 1, parent, routes); 87 } 88 } 89 90 public boolean differForOneLetter(String a, String b) { 91 int differNum = 0; 92 for (int i = 0, bound = a.length(); i < bound; i++) { 93 differNum += a.charAt(i) == b.charAt(i) ? 0 : 1; 94 } 95 return differNum == 1; 96 } 97 98 private static class Node { 99 String signature; 100 int flag; 101 List<Node> parent = new LinkedList<>(); 102 List<Node> nearTo = new LinkedList<>(); 103 104 @Override 105 public String toString() { 106 return signature + ":" + flag; 107 } 108 } 109 }