问题描述
Given two words (beginWord and endWord), and a dictionary’s word list, find all shortest transformation sequence(s) from beginWord to endWord , such that: Only one letter can be changed at a time Each transformed word must exist in the word list. Note that beginWord is not a transformed word. Note: Return an empty list if there is no such transformation sequence. All words have the same length. All words contain only lowercase alphabetic characters. You may assume no duplicates in the word list. You may assume beginWord and endWord are non-empty and are not the same. Example: 地址
问题分析
LeetCode 127. Word Ladder 的进阶,求从beginWord
到endWord
的最短路径具体是什么。像这种求具体路径的 ,那么一定用的的是 DFS, 而又要求最短路径 ,所以也用到 BFS 。所以这是一道 BFS + DFS 的经典难题。先将beginWord
加入到字符串集中,然后求每一个字符串的邻居,这样便建立了一个图的模型 HashMap<String, List<String>> neighbors
。 然后对该图利用 BFS 求每一个字符串到 beginWord
的最短路径值。HashMmap<String, Integer> distances
最后 利用 neighbors
与 distances
,通过 DFS 来求得从beignWord
到 endWord
的所有可能最短路径,注意每一步递归结束后对形成的path
进行回溯 。
后来想了一下,也可以不用建立 distances
,直接利用BFS来构建一张图(树)即可, 只不过要注意的一点是,每一层的str
可能会有相同,所以对 visited
的要求有所改变,具体见实现
代码实现
class Solution {
public List<List<String >> findLadders(String beginWord, String endWord, List<String > wordList) {
wordList.add(beginWord);
HashMap<String , List<String >> neighbors = getNeightbors(wordList);
HashMap<String , Integer> distances = getDistances(beginWord, wordList, neighbors);
ArrayList<String > path = new ArrayList<>();
List<List<String >> res = new ArrayList<>();
getShortestPaths(beginWord, endWord, neighbors, distances, path, res);
return res;
}
public HashMap<String , List<String >> getNeightbors(List<String > wordList) {
HashSet<String > dict = new HashSet<>(wordList);
HashMap<String , List<String >> neighbors = new HashMap<>();
for (int i = 0 ; i < wordList.size(); i++) {
String str = wordList.get(i);
neighbors.put(str, new ArrayList<>());
char[] chs = str.toCharArray();
for (int j = 0 ; j < chs.length; j++) {
for (char ch = 'a' ; ch <= 'z' ; ch++) {
if (ch != chs[j]) {
char tmp = chs[j];
chs[j] = ch;
String strChanged = new String (chs);
if (dict.contains(strChanged)) {
neighbors.get(str).add(strChanged);
}
chs[j] = tmp;
}
}
}
}
return neighbors;
}
public HashMap<String , Integer> getDistances(String beginWord, List<String > wordList, HashMap<String , List<String >> neighbors) {
HashSet<String > visited = new HashSet<>();
HashMap<String , Integer> distances = new HashMap<>();
LinkedList<String > queue = new LinkedList<>();
distances.put(beginWord, 0 );
queue.add(beginWord);
visited.add(beginWord);
while (! queue.isEmpty()) {
String cur = queue.poll();
for (String str : neighbors.get(cur)) {
if (!visited.contains(str)) {
distances.put(str, distances.get(cur) + 1 );
queue.add(str);
visited.add(str);
}
}
}
return distances;
}
public void getShortestPaths(String beginWord, String endWord, HashMap<String , List<String >> neighbors,
HashMap<String , Integer> distances, List<String > path, List<List<String >> res) {
path.add(beginWord);
if (beginWord.equals(endWord)) {
res.add(new ArrayList<>(path));
}else {
for (String neigbor : neighbors.get(beginWord)) {
if (distances.get(beginWord) + 1 == distances.get(neigbor)) {
getShortestPaths(neigbor, endWord, neighbors, distances, path, res);
}
}
}
path.remove(path.size() - 1 );
}
}
public List<List<String >> findLadders(String beginWord, String endWord, List<String > wordList) {
HashMap<String , List<String >> neighbors = getNeightbors(beginWord, wordList);
ArrayList<String > path = new ArrayList<>();
List<List<String >> res = new ArrayList<>();
getShortestPaths(beginWord, endWord, neighbors, path, res);
return res;
}
public HashMap<String , List<String >> getNeightbors(String beginWord, List<String > wordList) {
HashSet<String > set = new HashSet<>(wordList);
HashSet<String > visited = new HashSet<>();
HashMap<String , List<String >> neighbors = new HashMap<>();
LinkedList<String > queue = new LinkedList<>();
queue.add(beginWord);
visited.add(beginWord);
while (! queue.isEmpty()) {
int levelSize = queue.size();
ArrayList<String > levelStr = new ArrayList<>();
for (int count = 0 ; count < levelSize; count++) {
String str = queue.poll();
neighbors.put(str, new ArrayList<>());
char[] chs = str.toCharArray();
for (int i = 0 ; i < chs.length; i++) {
char tmp = chs[i];
for (char ch = 'a' ; ch <= 'z' ; ch++) {
if (ch != chs[i]) {
chs[i] = ch;
String strChange = new String (chs);
if (set.contains(strChange) && ! visited.contains(strChange)) {
neighbors.get(str).add(strChange);
queue.add(strChange);
levelStr.add(strChange);
}
chs[i] = tmp;
}
}
}
}
visited.addAll(levelStr);
}
return neighbors;
}
public void getShortestPaths(String beginWord, String endWord, HashMap<String , List<String >> neighbors, List<String > path, List<List<String >> res) {
path.add(beginWord);
if (beginWord.equals(endWord)) {
res.add(new ArrayList<>(path));
}else {
for (String neighbor : neighbors.get(beginWord)) {
getShortestPaths(neighbor, endWord, neighbors, path, res);
}
}
path.remove(path.size() - 1 );
}