单词接龙

单词接龙

127. 单词接龙

难度中等

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

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

说明:

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

示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5。

示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: 0

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

分析

常规 BFS

var ( 
    // 记录每个单词改变一个字母能得到的且存在于 wordList 的单词列表
    nexts map[string][]string
    // 记录从 beginWord 变换到当前单词需要的步数
    steps map[string]int
)

func ladderLength(beginWord string, endWord string, wordList []string) int {
    hasBegin, hasEnd := false, false
    for _, v := range wordList {
        if v == beginWord {
            hasBegin = true
        } else if v == endWord {
            hasEnd = true
        }
    }
    if !hasEnd {
        return 0
    }
    if !hasBegin {
        wordList = append(wordList, beginWord)
    }
    
    initNexts(wordList)
    initSteps(wordList)
    steps[beginWord] = 0

    queue := list.New()
    queue.PushBack(beginWord)
    for queue.Len() > 0 {
        word := queue.Remove(queue.Front()).(string)
        if word == endWord {
            return steps[word]+1
        }
        for _, next := range nexts[word] {
            if steps[next] <= steps[word]+1 {
                continue
            }
            steps[next] = steps[word]+1
            queue.PushBack(next)
        }
    }
    return 0
}

func initNexts(wordList []string) {
    n := len(wordList)
    nexts = make(map[string][]string, n)
    for i := 0; i < n-1; i++ {
        for j := i+1; j < n; j++ {
            s, t := wordList[i], wordList[j]
            if diffOneChar(s, t) {
                nexts[s] = append(nexts[s], t)
                nexts[t] = append(nexts[t], s)
            }
        }
    }
}

func diffOneChar(s, t string) bool {
    diffs := 0
    for i := 0; i < len(s); i++ {
        if s[i] != t[i] {
            diffs++
        }
    }
    return diffs == 1
}

func initSteps(wordList []string) {
    steps = make(map[string]int, len(wordList))
    for _, w := range wordList {
        steps[w] = len(wordList)
    }
}

TODO

  • 可以优化为双向 BFS
  • steps 的构造可以优化

变体 126. 单词接龙 II

约束相同,只是这次要返回所有从 beginWord 到 endWord 的最短转换序列。

解法也同 127,稍作调整即可。