Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
Return
[ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ]
Note:
题解:算是leetcode最恶心的一道题了。
跟Word Ladder一样要用BFS来搜索,但是要解决的问题是如何在BFS中保存路径。我们知道在DFS中 保存路径十分简单,但是在BFS中就很麻烦了。因为我们把点一层一层的放在队列里面,而不是一次把一条路径搜索完全。所以这里引进一种新的类Node如下:
class Node{ ArrayList<Node> prev; String me; int dist; public Node(String me,int dist){ this.me = me; this.prev = null; this.dist = dist; } }
使用该类,我们把搜索路径上遇到的每一个单词看成一个节点,me保存该节点对应的单词,dist保存从start单词搜索到该单词的最短距离,prev保存从start到该节点所有长度为dist的路径上该节点的前驱节点。
这样我们就可以在完成BFS后,从最后一个节点endNode(endNode对应单词end),利用前驱节点信息DFS出startNode到endNode的所有路径了。函数findPath实现这个功能。
另外在BFS的时候,我们需要一个map,来记录当前访问过哪些单词以及它们对应的节点。假设当前访问的节点是node,它对应的单词是t,我们通过修改t的每一位字母生成新的单词,如果新的单词在dict中且没有建立相应的节点(在map中没有记录),那么就建立相应的节点,并把该节点和单词的对应信息保存在map里面;如果当前生成的单词在dict中且已经有相应的节点,那么我们就看是否node也是它的前驱,如果是,把node加入它的前驱列表就可以了。
结束的条件是,我们生成了一个单词,它正好等于end,说明找到了从start到end的一条路径(不过为了找到所有到end的路径,所以当前队列中的元素还是要遍历完,因为它们在同一层上,也有可能可以达到end,所以用一个stop变量控制最外层的大循环);或者队列为空,说明找不到从start到end的路径。
最后代码如下:
1 public class Solution { 2 private List<List<String>> answer= new ArrayList<List<String>>(); 3 class Node{ 4 ArrayList<Node> prev; 5 String me; 6 int dist; 7 public Node(String me,int dist){ 8 this.me = me; 9 this.prev = null; 10 this.dist = dist; 11 } 12 } 13 private void findPath(Node endNode,ArrayList<String> result,String start){ 14 if(endNode.me.equals(start)){ 15 ArrayList<String> temp= new ArrayList<String>(result); 16 answer.add(temp); 17 return; 18 } 19 for(Node n:endNode.prev){ 20 result.add(0, n.me); 21 findPath(n, result, start); 22 result.remove(0); 23 } 24 } 25 public List<List<String>> findLadders(String start, String end, Set<String> dict) { 26 27 if(start == end){ 28 List<String> result = new ArrayList<String>(); 29 result.add(start); 30 result.add(end); 31 answer.add(result); 32 return answer; 33 } 34 35 Queue<Node> queue = new LinkedList<Node>(); 36 HashMap<String, Node> map = new HashMap<String,Node>(); 37 38 Node startNdoe = new Node(start,0); 39 queue.add(startNdoe); 40 map.put(start, startNdoe); 41 Node endNode = null; 42 int strLen = start.length(); 43 boolean stop = false; 44 45 while(!queue.isEmpty() && !stop){ 46 int thisLevel = queue.size(); 47 for(int i = 0;i < thisLevel;i++){ 48 Node node = queue.poll(); 49 for(int j = 0;j < strLen;j++){ 50 StringBuilder t = new StringBuilder(node.me); 51 char ch_t = node.me.charAt(j); 52 for(char k = 'a';k <= 'z';k++){ 53 if(k != ch_t){ 54 t.setCharAt(j, k); 55 if(dict.contains(t.toString())){ 56 Node v = map.get(t.toString()); 57 if(v == null){ 58 Node tempNode = new Node(t.toString(),node.dist+1); 59 tempNode.prev = new ArrayList<Node>(); 60 tempNode.prev.add(node); 61 queue.add(tempNode); 62 map.put(t.toString(), tempNode); 63 if(t.toString().equals(end)){ 64 endNode = tempNode; 65 stop = true; 66 } 67 } 68 else { 69 if(v.dist == node.dist+1) 70 v.prev.add(node); 71 } 72 } 73 } 74 } 75 } 76 } 77 } 78 if(endNode != null){ 79 ArrayList<String> result = new ArrayList<String>(); 80 result.add(endNode.me); 81 findPath(endNode,result,start); 82 } 83 return answer; 84 } 85 }