126. 单词接龙 II
需要注意的是,由于要找最短路径,连接 dot 与 lot 之间的边就不可以被记录下来,同理连接 dog 与 log 之间的边也不可以被记录。这是因为经过它们的边一定不会是最短路径。因此在广度优先遍历的时候,需要记录的图的关系如下图所示。
在广度优先遍历的时候,我们需要记录:从当前的单词 currWord 只变化了一个字符以后,且又在单词字典中的单词 nextWord 之间的单向关系(虽然实际上无向图,但是广度优先遍历是有方向的,我们解决这个问题可以只看成有向图),记为 from,它是一个映射关系:键是单词,值是广度优先遍历的时候从哪些单词可以遍历到「键」所表示的单词,使用哈希表来保存。
Java代码:还没看完,没看懂,有两个题解都得看看!
class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> res = new ArrayList<>();
Set<String> dict = new HashSet<>(wordList);
if (!dict.contains(endWord)) {
return res;
}
dict.remove(beginWord);
Map<String, Integer> steps = new HashMap<>();
steps.put(beginWord, 0); // 无向图,记录层数
Map<String, Set<String>> from = new HashMap<>();
boolean found = bfs(beginWord, endWord, dict, steps, from); // 构建无向图
if (found) {
Deque<String> path = new ArrayDeque<>();
path.add(endWord);
dfs(from, path, beginWord, endWord, res);
}
return res;
}
private boolean bfs(String beginWord, String endWord, Set<String> dict, Map<String, Integer> steps, Map<String, Set<String>> from) {
int wordLen = beginWord.length();
int step = 0;
boolean found = false;
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
while (!queue.isEmpty()) {
step++;
int size = queue.size();
for (int i = 0; i < size; i++) { // 遍历队列
String currWord = queue.poll();
char[] charArray = currWord.toCharArray();
for (int j = 0; j < wordLen; j++) { // 单词数组
char origin = charArray[j];
for (char c = 'a'; c <= 'z'; c++) { // 对单词的每一个位进行更替
charArray[j] = c;
String nextWord = String.valueOf(charArray);
if (steps.containsKey(nextWord) && steps.get(nextWord) == step) { // Map<String, Integer> steps
from.get(nextWord).add(currWord); // from: 广度优先遍历的时候从哪些单词可以遍历到「键」所表示的单词
}
if (!dict.contains(nextWord)) {
continue;
}
dict.remove(nextWord);
queue.offer(nextWord);
from.putIfAbsent(nextWord, new HashSet<>()); // from是映射图
from.get(nextWord).add(currWord); // 当前值映射到源,以源为头去add,有向图
steps.put(nextWord, step);
if (nextWord.equals(endWord)) {
found = true;
}
}
charArray[j] = origin;
}
}
if (found) {
break;
}
}
return found;
}
private void dfs(Map<String, Set<String>> from, Deque<String> path, String beginWord, String cur, List<List<String>> res) {
if (cur.equals(beginWord)) {
res.add(new ArrayList<>(path));
return;
}
for (String precursor : from.get(cur)) {
path.addFirst(precursor);
dfs(from, path, beginWord, precursor, res);
path.removeFirst();
}
}
}