题目
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> … -> sk:
每一对相邻的单词只差一个字母。
对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
sk == endWord
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。
示例 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” 不在字典中,所以无法进行转换。
代码:
// 建立映射关系
func getWordMap(wordList []string, beginWord string) map[string]int {
// 创建字母和数字的映射关系
wordMap := make(map[string]int)
// 遍历单词列表,和数字建立联系
for i, word := range wordList {
// 如果该字母已经存在已经有的映射关系,则不重复建立映射关系
// 如果该字母不存在没有建立映射关系,则新建立映射关系
if _, ok := wordMap[word]; !ok {
if word != beginWord {
wordMap[word] = i
}
}
}
return wordMap
}
// 列举可能的情况
func getCandidates(word string) []string {
var res []string
// 遍历26个英文字母
for i := 0; i < 26; i++ {
// 因为word的长度不止一个,因此遍历多个字母的情况,插入单词的不同位置
for j := 0; j < len(word); j++ {
// 如果列举的字符不是当前字符,则将该字符添加进列表中
if byte(int('a')+i) != word[j] {
res = append(res, word[:j]+string(rune(int('a')+i))+word[j+1:])
}
}
}
return res
}
// https://leetcode-cn.com/problems/word-ladder/description/
func ladderLength(beginWord string, endWord string, wordList []string) int {
// 创建映射关系列表,beginWord字符串列表,节点数量
wordMap, beginwordlist, count := getWordMap(wordList, beginWord), []string{beginWord}, 0
// 如果beginword不为空,则执行以下逻辑
// 如果beginword为空,则返回0
for len(beginwordlist) > 0 {
// 初始化转换序列长度,长度为1,代表beginWord本身,即beginWord->
count++
// 初始化beginWord长度
beginwordlen := len(beginwordlist)
// 遍历开始的字符串
for i := 0; i < beginwordlen; i++ {
// 初始化首个字符
word := beginwordlist[0]
// 更新字符串列表
beginwordlist = beginwordlist[1:]
// 获取所有可能的情况
candidates := getCandidates(word)
// 遍历所有可能的情况
for _, candidate := range candidates {
// 如果该种情况的单词在映射列表里
if _, ok := wordMap[candidate]; ok {
// 如果该种情况的单词=目标单词,则返回2,表示从beginWord可以直接到endWord
if candidate == endWord {
// 直接返回2
return count + 1
}
// 如果是该种情况的单词!= 目标单词,删除该种情况下的单词
delete(wordMap, candidate)
// 将该种情况下的单词重新添加进beginwordlist进行后续循环
beginwordlist = append(beginwordlist, candidate)
}
}
}
}
return 0
}