package com.interview.books.leetcodeoj;
import java.util.*;
/**
* Created_By: stefanie
* Date: 14-12-26
* Time: 下午10:26
*/
public class LOJ126_WordLadderII {
//Solution:
// 1. to find all shortest path solution, should use level-order traversal
// 2. to build the path, need create a retrieval data structure, Node(String word, List<Node> prev, int depth)
// 3. use a Map<String, Node> map to mark if a word is visited and tracking it's prev
// 4. while(!queue.isEmpty() && !found) do traversal
// 5. if(found) use backtracing(permutation) to find all the path.
//Important:
// 1. tracking depth in Node, only if (nextNode.depth == node.depth + 1) nextNode.prev.add(node);
// 2. set found = true when found a solution, but need finish visiting this layer
// 3. chars[i] = original; when permutation on char[i] to 'a' to 'z'
// 4. when permutate to get path, clone path and add prev in until prev is start.
class Node{
String word;
int depth = 0;
List<Node> prev = new ArrayList();
public Node(String word, int depth){
this.word = word;
this.depth = depth;
}
}
List<List<String>> paths;
public List<List<String>> findLadders(String start, String end, HashSet<String> dict) {
paths = new ArrayList();
if(start.equals(end)){
List<String> path = new ArrayList();
path.add(start);
paths.add(path);
return paths;
}
Queue<Node> queue = new LinkedList();
Map<String, Node> visited = new HashMap();
Node startNode = new Node(start, 0);
queue.offer(startNode);
visited.put(start, startNode);
boolean found = false;
while(!queue.isEmpty() && !found){
int levelSize = queue.size();
for(int k = 0; k < levelSize; k++){
Node node = queue.poll();
char[] chars = node.word.toCharArray();
for(int i = 0; i < chars.length; i++){
char original = chars[i];
for(char ch = 'a'; ch <= 'z'; ch++){
if(ch == original) continue;
chars[i] = ch;
String next = String.valueOf(chars);
if(dict.contains(next)){
Node nextNode = visited.get(next);
if(nextNode != null) {
if (nextNode.depth == node.depth + 1) nextNode.prev.add(node);
} else {
nextNode = new Node(next, node.depth + 1);
nextNode.prev.add(node);
visited.put(next, nextNode);
if(next.equals(end)) found = true;
else queue.add(nextNode);
}
}
}
chars[i] = original;
}
}
}
if(found){
List<String> path = new ArrayList();
path.add(end);
getPath(visited.get(end), path, start);
}
return paths;
}
public void getPath(Node node, List<String> path, String start){
if(node.word.equals(start)){
paths.add(path);
}
for (Node prev : node.prev) {
List<String> current = new ArrayList<String>(path);
current.add(0, prev.word);
getPath(prev, current, start);
}
}
public static void main(String[] args){
HashSet<String> dict = new HashSet<>();
dict.add("hot");
dict.add("dotProduct");
dict.add("dog");
LOJ126_WordLadderII finder = new LOJ126_WordLadderII();
List<List<String>> paths = finder.findLadders("hot", "hot", dict);
for(List<String> path : paths){
for(String word : path){
System.out.print(word + ", ");
}
System.out.println();
}
}
}