一起刷LeetCode——单词接龙(BFS)

129 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情

单词接龙

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk:

每一对相邻的单词只差一个字母。  对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。 sk == endWord 给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。

来源:力扣(LeetCode) 链接:leetcode.cn/problems/wo…

分析

常规BFS

  • 这道题有点像之前写过的最小基因变化,只不过最小基因变化元素的每一位上有4种可能,单词接龙中的元素每一位上有26种可能,首先看起始单词和结束单词是否在单词库,如果有不存在的,返回0,如果都在,遍历起始单词的每一个字母,变化一位之后看是否在单词库里,如果有长度加一,如果没有返回0,同事记录当前的变化,中间如果有单词没有在单词库中,返回0,一直变化到结束单词,次数就是题目的答案
代码
var ladderLength = function(beginWord, endWord, wordList) {
    let wordSet = new Set(wordList)
    let  q = [beginWord]
    let level = 1
    while(q.length){
        let lsize = q.length
        while(lsize-- > 0){
            let word = q.shift()
            if(word === endWord)     return level
            for(let i=0; i<word.length; i++){
                for(let j=0; j<26; j++){
                    let newWord = word.slice(0, i) + String.fromCharCode(j+97) + word.slice(i+1)
                    if(wordSet.has(newWord)){
                        wordSet.delete(newWord);
                        q.push(newWord)
                    }
                }
            }
        }
        level++
    }
    return 0
};

双向BFS

  • 假如每个节点的分支数量相同,搜索空间会随着层数的增长指数级增加,如果每层都是满二叉树扩展,节点的数量就是以2为底数的指数式增长,何况单词接龙每个位置上有26中可能。因此,可以使用两个同时进行的BFS减少搜索空间,一个从起始单词开始,一个从结束单词开始,当某一时刻,两个BFS访问了同一个节点就停止搜索
代码
var ladderLength = function(beginWord, endWord, wordList) {
    const charMap = buildCharMap()
    const wordSet = new Set(wordList)
    if (!wordSet.has(endWord)) return 0

    let leftSet = new Set([beginWord]), rightSet = new Set([endWord]), level = 1
    
    const helper = (set1, set2) => {
        const setArr = Array.from(set1)
        for (let i = 0;  i < setArr.length; i++) {
            const word = setArr[i]
            for (let i = 0; i < word.length; i++) {
                for (const c of charMap) {
                    const newWord = word.slice(0, i) + c + word.slice(i + 1)
                    if (set2.has(newWord)) return true
                    if (wordSet.has(newWord)) { 
                        set1.add(newWord)
                        wordSet.delete(newWord)
                    }
                }
            }
            set1.delete(word)
        }
    }
    
    while (leftSet.size && rightSet.size) {
        level++
        if (helper(leftSet, rightSet)) return level
        
        level++
        if (helper(rightSet, leftSet)) return level
    }
        
    return 0
};

const buildCharMap = () => {
    const map = []
    
    for (let i = 0; i < 26; i++) {
        map.push(String.fromCharCode(i + 97))
    }
    
    return map
}

总结

  • 本题是基于最小基因变化的基础上的扩展,当每个位置都有26种可能的时候,可以一个方向搜索,为了优化搜索空间,可以选择使用双向BFS来有效减少搜索空间
  • 今天也有是有收获的一天