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.
For example,
Given:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]
Return
[
[“hit”,”hot”,”dot”,”dog”,”cog”],
[“hit”,”hot”,”lot”,”log”,”cog”]
]
题意:127题的followup,要求不单是求最少变换次数,还要返回所有符合最短变换次数的具体变换。
思路:
先用bfs找寻最短路径,同时为每个单词标上它的最短等级;
然后用dfs搜索所有最短路径,搜索的条件就是下一个单词的最短等级等于当前单词最短等级+1.
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
HashSet<String> dict = new HashSet<>(wordList);
dict.add(beginWord);
HashMap<String, Integer> depth = new HashMap<>();
HashMap<String, List<String>> neighbours = new HashMap<>();
for (String word : wordList) {
neighbours.put(word, new ArrayList<>());
}
neighbours.put(beginWord, new ArrayList<>());
List<List<String>> res = new ArrayList<>();
List<String> subres = new ArrayList<>();
bfs(beginWord, endWord, dict, depth, neighbours);
dfs(beginWord, endWord, dict, neighbours, depth, subres, res);
return res;
}
public void bfs(String beginWord, String endWord, HashSet<String> dict, HashMap<String, Integer> depth, HashMap<String, List<String>> neighbours) {
Queue<String> q = new LinkedList<>();
q.add(beginWord);
depth.put(beginWord, 0);
while (!q.isEmpty()) {
int size = q.size();
boolean found = false;
for (int i = 0; i < size; i++) {
String cur = q.poll();
int curDistance = depth.get(cur);
List<String> nextWords = getNextWords(cur, dict);
for (String nextWord : nextWords) {
neighbours.get(cur).add(nextWord);
if (!depth.containsKey(nextWord)) {
depth.put(nextWord, curDistance + 1);
if (endWord.equals(nextWord)) {
found = true;
} else {
q.offer(nextWord);
}
}
}
}
if (found) {
break;
}
}
}
//bug 这里不能过滤掉depth中已经有的word,否则会导致某些词的neighbours有缺失
// public List<String> getNextWords(String word, HashSet<String> dict, HashMap<String, Integer> depth) {
public List<String> getNextWords(String word, HashSet<String> dict) {
List<String> list = new ArrayList<>();
char[] chars = word.toCharArray();
for (int i = 0; i < word.length(); i++) {
for (char c = ‘a’; c <= ‘z’; c++) {
if (chars[i] == c) {
continue;
}
char origin = chars[i];
chars[i] = c;
String nextWord = new String(chars);
// if (dict.contains(nextWord) && !depth.containsKey(nextWord)) {
if (dict.contains(nextWord)) {
list.add(nextWord);
}
chars[i] = origin;
}
}
return list;
}
private void dfs(String cur, String end, Set<String> dict, HashMap<String, List<String>> nodeNeighbors, HashMap<String, Integer> distance, List<String> solution, List<List<String>> res) {
solution.add(cur);
if (end.equals(cur)) {
res.add(new ArrayList<>(solution));
} else {
List<String> neighbours = nodeNeighbors.get(cur);
for (String next : nodeNeighbors.get(cur)) {
if (distance.get(next) == distance.get(cur) + 1) {
dfs(next, end, dict, nodeNeighbors, distance, solution, res);
}
}
}
solution.remove(solution.size() - 1);
}