【每日leecode】Leecode 127. 单词接龙

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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

bfs解法

bfs基础模板

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
}

双源bfs解法

伪代码

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
}

 

 

 

你可能感兴趣的:(每日leecode,bfs)