bfs经典题目
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 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" 不在字典中,所以无法进行转换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-ladder
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
type node struct
//init 初始化的一些操作,注册一些map
//初始化队列以及节点
queue := []node{root}
for len(queue) > 0 {
//开始遍历对每层做一些操作 计步 出入度
temp := make([]node, 0) //用户记录下一层的节点
for _, v := range queue {
//开始对每层的节点进行操作
}
queue = temp //赋值
}
q.push(start) // 初始节点放入队列
step = 0 // 初始化步长为0
while not q.empty(): // 当前节点不为空
++step // 扩展一层节点
size = q.size() // 当前这一层节点的个数
while size-- > 0: // 当前这一层节点数量大于0
node = q.pop() // 不断出队
new_nodes = expand(node) // 扩展下一层的节点
if goal in new_nodes: return step + 1 // 找到结果step+1返回步长
q.append(new_nodes) // 如果没有找到结果,把下一层的所有节点加入队列
return NOT_FOUND // 队列全部结束,没有找到结果
func ladderLength(beginWord string, endWord string, wordList []string) int {
//按照套路先注册单词
dicMap := make(map[string]byte)
for _, v := range wordList {
dicMap[v] = '1'
}
//没有直接fanhui
if _, ok := dicMap[endWord]; !ok {
return 0
}
//初始化队列
queue := []string{beginWord}
ls := len(beginWord)
step := 0
for len(queue) > 0 {
step++
temp := make([]string, 0)
for _, v := range queue {
wordSli := []rune(v)
//循环每个位
for i := 0; i < ls; i++ {
char := wordSli[i]
//遍历26哥字母
for c := 'a'; c <= 'z'; c++ {
//当前直接跳过
if char == c {
continue
}
wordSli[i] = c
tempStr := string(wordSli)
//如果不存在直接跳过
if _, ok := dicMap[tempStr]; !ok {
continue
}
if tempStr == endWord {
return step+1
}
//删除不走回头路
delete(dicMap, tempStr)
//加入下一次循环
temp = append(temp, tempStr)
}
wordSli[i] = char//复位,注意 如果不复位,单词发送改变 循环下一位的时候以及和原来不同了
}
}
fmt.Println(temp)
queue = temp
}
return 0
}
s1.insert(start) // 方便使用HashSet
s2.insert(end) // start和end放入两个set
step = 0 // 初始化步长为0
while not (s1.empty() || s2.empty()): // 当两个set都不为空,循环执行
++step // 步长+1
swap*(s1, s2) // 交替从左端扩展和从右端扩展
s = {} // 定义新的空集合
for node in s1: // 当前需要扩展的这一层节点进行遍历
new_nodes = expand(node) // 扩展下一层节点
if any(new_nodes) in s2: return step + 1 // 新的节点在s2集合中,返回step+1,找到路径
s.append(new_nodes) // 如果没有找到结果,把下一层的所有节点加入队列
s1 = s // 临时的集合赋值给s1,即把已经走的路径存储起来
return NOT_FOUND // 队列全部结束,没有找到结果
注意 在初始化的时候使用set 等数据结构是为了中间判断方便,不再使用队列,但是大体思路不变针对上面的模板改几行代码就可以
func ladderLength(beginWord string, endWord string, wordList []string) int {
//按照套路先注册单词
dicMap := make(map[string]byte)
for _, v := range wordList {
dicMap[v] = '1'
}
//没有直接fanhui
if _, ok := dicMap[endWord]; !ok {
return 0
}
//初始化起止注册表
q1 := make(map[string]byte)
q2 := make(map[string]byte)
q1[beginWord] = '1'
q2[endWord] = '1'
ls := len(beginWord)
step := 0
for len(q1) > 0 && len(q2) > 0 {
step++
if len(q1) > len(q2) {
q1, q2 = q2, q1
}
temp := make(map[string]byte)
for v := range q1 {
wordSli := []rune(v)
//循环每个位
for i := 0; i < ls; i++ {
char := wordSli[i]
//遍历26哥字母
for c := 'a'; c <= 'z'; c++ {
//当前直接跳过
if char == c {
continue
}
wordSli[i] = c
tempStr := string(wordSli)
//修改判断 如果 tempStr 在 q2 中则返回
if _, ok := q2[tempStr]; ok {
return step+1
}
//如果不存在直接跳过
if _, ok := dicMap[tempStr]; !ok {
continue
}
//删除不走回头路
delete(dicMap, tempStr)
//加入下一次循环
temp[tempStr] = '1'
}
wordSli[i] = char//复位,注意 如果不复位,单词发送改变 循环下一位的时候以及和原来不同了
}
}
q1 = temp
}
return 0
}