Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
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:
- All words have the same length.
- All words contain only lowercase alphabetic characters.
这道题也是一道非常恶心的题,巨多繁琐的操作,严格的时间限制。别的不说了,直接上代码吧
public static ArrayList<ArrayList<String>> findLadders(String start,
String end, HashSet<String> dict) {
ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();// results
int currLen = 0;
boolean found = false;
/**
* we need a hash set to store all unVisited words
*/
Set<String> unVisited = new HashSet<String>(dict);
unVisited.add(end);
/**
* <String, Queue> contain all the adjacent words that is discover in
* its previous level
*/
HashMap<String, Queue<String>> adjMap = new HashMap<String, Queue<String>>();
for (String word : unVisited)
adjMap.put(word, new LinkedList<String>());
/**
* we need a queue to do BFS
*/
Queue<String> queue = new LinkedList<String>();
queue.add(start);
/**
* we need a hashset to store all words at the same level
*/
Set<String> visitedThisLev = new HashSet<String>();
int currLev = 1;
int nextLev = 0;
/**
* Now begin BFS and try to finish adjMap which is stored for all
* unvisited words that are one character change from current word
*/
while (!queue.isEmpty()) {
String curLadder = queue.poll();
currLev--;
for (String nextLadder : getNextLadder(curLadder, unVisited)) {
if (visitedThisLev.add(nextLadder)) {
nextLev++;
queue.add(nextLadder);
}
adjMap.get(nextLadder).add(curLadder);
if (nextLadder.equals(end) && !found) {
found = true;
currLen += 2;
}
}
if (currLev == 0) {
if (found)
break;
unVisited.removeAll(visitedThisLev);
currLev = nextLev;
nextLev = 0;
currLen++;
}
}
/**
* if we find the path, we can construct the path now!
*/
if (found) {
LinkedList<String> p = new LinkedList<String>();
p.addFirst(end);
getLadders(start, end, p, result, adjMap, currLen);
}
return result;
}
// get all unvisited words that are one character change from current word
private static ArrayList<String> getNextLadder(String curLadder,
Set<String> unVisited) {
ArrayList<String> nextLadders = new ArrayList<String>();
StringBuffer replace = new StringBuffer(curLadder);
for (int i = 0; i < curLadder.length(); i++) {
char old = replace.charAt(i);
for (char ch = 'a'; ch <= 'z'; ch++) {
replace.setCharAt(i, ch);
String replaced = replace.toString();
if (ch != curLadder.charAt(i) && unVisited.contains(replaced)) {
nextLadders.add(replaced);
}
}
replace.setCharAt(i, old);
}
return nextLadders;
}
// DFS to get all possible path from start to end
private static void getLadders(String start, String curLadder,
LinkedList<String> p, ArrayList<ArrayList<String>> result,
HashMap<String, Queue<String>> adjMap, int length) {
if (curLadder.equals(start)) {
result.add(new ArrayList<String>(p));
} else if (length > 0) {
Queue<String> adjs = adjMap.get(curLadder);
for (String lad : adjs) {
p.addFirst(lad);
getLadders(start, lad, p, result, adjMap, length - 1);
p.removeFirst();
}
}
}