🌈【LeetCode 126. 单词接龙 II 】- JavaScript(BFS+DFS)

139 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


【LeetCode 126. 单词接龙 II 】- JavaScript(BFS+DFS)

题目描述

按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s1 -> s2 -> ... -> sk 这样的单词序列,并满足:

  • 每对相邻的单词之间仅有单个字母不同。
  • 转换过程中的每个单词 si(1 <= i <= k)必须是字典 wordList 中的单词。注意,beginWord 不必是字典 wordList 中的单词。
  • sk == endWord

给你两个单词 beginWord 和 endWord ,以及一个字典 wordList 。请你找出并返回所有从 beginWord 到 endWord 的 最短转换序列 ,如果不存在这样的转换序列,返回一个空列表。每个序列都应该以单词列表 [beginWord, s1, s2, ..., sk] 的形式返回。

示例 1:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] 输出:[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]] 解释:存在 2 种最短的转换序列: "hit" -> "hot" -> "dot" -> "dog" -> "cog" "hit" -> "hot" -> "lot" -> "log" -> "cog"

DFS+BFS

思路分析:

整体的的思路:分析完这个题目之后就知道我们应该使用DFS和BFS结合来做,首先我们要做的是构建出这个无向无权图,根绝题意我们可以知道,与一个word相差一个字母的单词都是该word的邻居节点。后面补充这里如何操作效率会高。我们将该图建立起来之后,通过BFS一层层的遍历,在遍历的过程中我们可以轻松的得到每个单词举例beginWord的层次信息 wordLevel。以及每个word的父亲节点(即与该节点相连的节点是那些)wordConnection.根绝这两个信息,可以帮助我们快速的进行DFS遍历。核心就是BFS构图,DFS遍历。具体如下:

  • bfs构建最短路径的graph。(注意每一层的元素,不同的元素对应的下一个节点可能是相同的,当前层需要构建完graph之后再删除下一层的节点)。

  • dfs回溯获取最短路径的所有可能。(注意如果在开始和结束直接回溯,找到结果之后不能直接return,否则执行不到remove最后一个元素)。

var findLadders = function (beginWord, endWord, wordList) {
  const wordSet = new Set(wordList);
  wordSet.add(beginWord);
  if (!wordSet.has(endWord)) return [];
  const levelMap = new Map();
  const wordMap = new Map();
  const queue = [beginWord];
  const visited = new Set();
  let finished = false;
  let level = 0;
  levelMap.set(beginWord, 0);
  visited.add(beginWord);
  while (queue.length > 0) {
    let levelSize = queue.length;
    level++;
    for (let i = 0; i < levelSize; i++) {
      const word = queue.shift();
      for (let j = 0; j < word.length; j++) {
        for (let code = 97; code <= 122; code++) {
          const newWord =
            word.slice(0, j) + String.fromCharCode(code) + word.slice(j + 1);
          if (!wordSet.has(newWord)) continue;
          if (wordMap.has(newWord)) {
            wordMap.get(newWord).push(word);
          } else {
            wordMap.set(newWord, [word]);
          }
          if (visited.has(newWord)) continue;
          if (newWord === endWord) finished = true;
          levelMap.set(newWord, level);
          queue.push(newWord);
          visited.add(newWord);
        }
      }
    }
  }
  if (!finished) return [];
  const res = [];
  dfs(res, [], beginWord, endWord, wordMap, levelMap);
  return res;
};

function dfs(res, path, beginWord, word, wordMap, levelMap) {
  if (word === beginWord) {
    res.push([beginWord, ...path]);
    return;
  }
  path.unshift(word);
  if (wordMap.get(word)) {
    for (const parent of wordMap.get(word)) {
      if (levelMap.get(parent) + 1 === levelMap.get(word)) {
        dfs(res, path, beginWord, parent, wordMap, levelMap);
      }
    }
  }
  path.shift();
}

思考

注意点:只能说非常繁琐,BFS+DFS的结合,中间剪枝也挺麻烦的。这到题目可以说是名副其实的困难题。真的挺难。


感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤