当年这道题出来的时候是有名的难题。
我做的时候也是叹为观止。不过现在套路大家都熟了。
Word ladder就是图的问题,所以先建图
然后找所有的最短路径。
找最短路径的办法就是BFS。
这里由于我们要求出所有的最短路径所以要按level order来做。
我们做BFS的时候对于每个点它从哪里来的也记一下。
然后回溯回去重建路径就好了。
这么看的话也不是很难。
就是把大问题分解成小问题,然后分头解决小问题。
人的大脑容易虽然很大,可是注意力是有限的, 所以要分解成小问题
这就是一个BFS找最短路径然后重建所有最短路径的问题。
class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
Map<String, Set<String>> graph = buildGraph(beginWord, wordList);
//bfs to find shortest path and record upper streams
Map<String, Set<String>> upperStreams = new HashMap<>();
int dist = bfsHelper(beginWord, endWord, graph, upperStreams);
//reconstruct the path;
List<List<String>> ans = new ArrayList<>();
if (dist == -1) return ans;
LinkedList<String> path = new LinkedList<>();
path.add(endWord);
dfsHelper(path, upperStreams, ans, beginWord); // reconstruct all paths
return ans;
}
private void dfsHelper(LinkedList<String> path, Map<String, Set<String>> upperStreams,
List<List<String>> ans, String beginWord ) {
//base case;
if (path.get(0).equals(beginWord)) {
ans.add(new ArrayList<>(path));
return;
}
String cur = path.get(0);
for (String prev : upperStreams.get(cur)) {
path.addFirst(prev);
dfsHelper(path, upperStreams, ans, beginWord);
path.removeFirst();
}
}
private int bfsHelper(String beginWord, String endWord, Map<String, Set<String>> graph, Map<String, Set<String>> upperStreams ) {
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
Set<String> visited = new HashSet<>();
visited.add(beginWord);
int level = 1;
boolean found = false;
while (!queue.isEmpty()) {
int size = queue.size();
Set<String> visitedAtThisLevel = new HashSet<>(); // need to collection all path so can't put to visited immediately
for (int i = 0; i < size; i++) {
String w = queue.poll();
// expand;
if (graph.get(w) == null) continue;
for (String next : graph.get(w)) {
if (visited.contains(next)) continue;
upperStreams.putIfAbsent(next, new HashSet<>());
upperStreams.get(next).add(w);
if (next.equals(endWord)) found = true;
if (!visitedAtThisLevel.contains(next)) queue.add(next);
visitedAtThisLevel.add(next);
}
}
visited.addAll(visitedAtThisLevel);
if (found) return level;
level++;
}
return -1;
}
private Map<String, Set<String>> buildGraph(String beginWord, List<String> wordList){
wordList.add(beginWord);
Map<String, Set<String>> graph = new HashMap<>();
for (int i = 0; i < wordList.size(); i++) {
for (int j = i + 1; j < wordList.size(); j++) {
if (diffOne(wordList.get(i), wordList.get(j)) ) {
String w1 = wordList.get(i), w2 = wordList.get(j);
graph.putIfAbsent(w1, new HashSet<>());
graph.putIfAbsent(w2, new HashSet<>());
graph.get(w1).add(w2);
graph.get(w2).add(w1);
}
}
}
return graph;
}
private boolean diffOne(String w1, String w2) {
int count = 0;
for (int i = 0; i < w1.length(); i++) {
if (w1.charAt(i) != w2.charAt(i)) count++;
if (count > 1) return false;
}
return count == 1;
}
}