前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【一天一大 lee】单词接龙 (难度:中等) - Day20201105

【一天一大 lee】单词接龙 (难度:中等) - Day20201105

作者头像
前端小书童
发布2020-11-11 14:18:44
4350
发布2020-11-11 14:18:44
举报
文章被收录于专栏:前端小书童前端小书童

题目:

给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例:

  1. 示例1:
代码语言:javascript
复制
输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5。
  1. 示例2:
代码语言:javascript
复制
输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: 0

解释: endWord "cog" 不在字典中,所以无法进行转换。

抛砖引玉

思路:

特殊情况: 如果字典中不包含endWord则直接返回0

本题可以从两个角度来思考解法:

  1. 收集wordList中每个单词完成一次转换对应的结果, 再从beginWord中逐个字符尝试替换,直到找到endWord,返回最小的查找次数
  2. 从beginWord开始逐个使用a到z字符替换每个位置的字符,替换的结果在wordList中 则记录替换后的字符和步数, 再将替换后的字符逐个使用a到z字符替换每个位置的字符... 依次类推来加步数 最后返回找到endWord,返回最小步数

广度优先搜索 + 优化建图

抛砖引玉

  • 声明map记录wordList中每个单词被替换单个字符后对应的子集:*og -> "dog","log","cog"
  • 为了防止重复枚举,声明visitedMap通过哈希记录已经枚举过的单词不在重复参与枚举
代码语言:javascript
复制
/**
 * @param {string} beginWord
 * @param {string} endWord
 * @param {string[]} wordList
 * @return {number}
 */
var ladderLength = function(beginWord, endWord, wordList) {
  if (!wordList.includes(endWord)) return 0
  let map = new Map(),
 len = wordList.length;

  // 记录替换字符后的子集
  for (let i = 0; i < len; i++) {
   const item = wordList[i],
     itemLen = wordList[i].length
    for (let j = 0; j < itemLen; j++) {
      const newStr = wordList[i].substring(0, j) + '*' + wordList[i].substring(j + 1, itemLen);
      if (!map.has(newStr)) map.set(newStr, [])
      map.get(newStr).push(wordList[i])
    }
  }
 // 从 beginWord开始枚举可能替换的结果
  let queue = [[beginWord, 1]],
    visitedMap = new Map([[beginWord, true]]);
  while (queue.length) {
 let [word, level] = queue.shift(),
  itemLen = word.length;
    for (let i = 0; i < itemLen; i++) {
      const newStr = word.substring(0, i) + '*' + word.substring(i + 1, itemLen);
      if (map.has(newStr)) {
        for (let j = 0; j < map.get(newStr).length; j++) {
    const child = map.get(newStr)[j]
  //   遇到endWord终止
    if (child === endWord) return level + 1
  //   避免重复枚举字符
          if (!visitedMap.has(child)) {
            visitedMap.set(child, true)
            queue.push([child, level + 1]);
          }
        }
      }
    }
  }
  return 0
};

广度优先搜索 + 转换单词

  • 题目限定单词只由小写字母组成,那么在转换字符时,只需从beginWord开始, 遍历转换位置逐个替换成a到z的字符就可以枚举所有转换元素,记录每个转换后的元素和转到到其所需步骤。
  • 将转换后的元素再次推送到队列中继续枚举知道遇到endWord返回
代码语言:javascript
复制
/**
 * @param {string} beginWord
 * @param {string} endWord
 * @param {string[]} wordList
 * @return {number}
 */
var ladderLength = function(beginWord, endWord, wordList) {
  let wordSet  = new Set(wordList),
        queue = [[beginWord, 1]];
  while (queue.length) {
    let len = queue.length
    for (let i = 0; i < len; i++) {
      const [word, level] = queue.shift();
      if (word == endWord) return level +1
      for (let i = 0; i < word.length; i++) {
  //   枚举可能存在的转换
        for (let c = 1; c <= 26; c++) {
          const newWord = word.slice(0, i) + String.fromCharCode(97+c) + word.slice(i + 1)
          if (wordSet.has(newWord)) {
            queue.push([newWord, level + 1]);
            wordSet.delete(newWord);
          }
        }
      }
    }
  }
  return 0
};

注意: 上面广度优先搜索方法转换过程存在顺序,队列尾部的元素依赖队列头部元素先转接,则queue需要遵循队列先进先出原则(FIFO)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小书童 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目:
    • 示例:
    • 抛砖引玉
      • 广度优先搜索 + 优化建图
        • 广度优先搜索 + 转换单词
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档