Leetcode刷题笔记——广度优先搜索(BFS)

Leetcode刷题笔记——广度优先搜索篇(BFS)

一、二叉树中的BFS

第一题:二叉树的最大深度

Leetcode104. 二叉树的最大深度:简单题 (详情点击链接见原题)

给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数

python完整题解代码

from collections import deque


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        queue = deque()
        queue.append(root)
        max_depth = 0
        while queue:
            n = len(queue)
            while n > 0:
                temp = queue.popleft()
                if temp.left:
                    queue.append(temp.left)
                if temp.right:
                    queue.append(temp.right)
                n -= 1
            max_depth += 1
        return max_depth

第二题:相同的树

Leetcode100. 相同的树:简单题 (详情点击链接见原题)

给你两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同

python完整题解代码

class Solution:
    def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
        queue = deque()
        queue.append((p, q))
        while queue:
            p_tree, q_tree = queue.popleft()
            if not p_tree and not q_tree:
                continue
            if (not p_tree or not q_tree) or p_tree.val != q_tree.val:
                return False
            queue.append((p_tree.left, q_tree.left))
            queue.append((p_tree.right, q_tree.right))
        return True

第三题:二叉树的层序遍历

Leetcode102. 二叉树的层序遍历:中等题 (详情点击链接见原题)

给你二叉树的根节点 root ,返回其节点值的层序遍历 。 (即逐层地,从左到右访问所有节点)

python完整题解代码

class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []
        queue = deque()
        queue.append(root)
        res = []
        while queue:
            n = len(queue)
            ans = []
            while n > 0:
                temp = queue.popleft()
                ans.append(temp.val)
                if temp.left:
                    queue.append(temp.left)
                if temp.right:
                    queue.append(temp.right)
                n -= 1
            res.append(ans)
        return res

第四题:二叉树的层序遍历 II

Leetcode107. 二叉树的层序遍历 II:中等题 (详情点击链接见原题)

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历

class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []
        queue = deque()
        queue.append(root)
        res = []
        while queue:
            n = len(queue)
            ans = []
            while n > 0:
                temp = queue.popleft()
                ans.append(temp.val)
                if temp.left:
                    queue.append(temp.left)
                if temp.right:
                    queue.append(temp.right)
                n -= 1
            res.append(ans)
        return res[::-1]   # 与上题唯一的区别

第五题:二叉树的锯齿形层序遍历

Leetcode103. 二叉树的锯齿形层序遍历:中等题 (详情点击链接见原题)

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

python完整题解代码

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Solution:
    def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []
        res = []  # 用来保存最终结果集
        queue = deque([root])
        while queue:
            tmp = deque()
            for _ in range(len(queue)):
                node = queue.popleft()
                if len(res) % 2 == 0:  # res的长度对2取模为偶数时, 准备插入的是奇数层:(插入队列尾部)
                    tmp.append(node.val) 
                else:    # res的长度对2取模为奇数时, 准备插入的是偶数层:(插入队列头部)
                    tmp.appendleft(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(list(tmp))    # 将该层元素加入到结果集
        return res

第六题:二叉树的右视图

Leetcode199. 二叉树的右视图:中等题 (详情点击链接见原题)

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值

python完整题解代码

from collections import deque


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        queue = deque()
        queue.append(root)
        right_view = []
        while queue:
            level_size = len(queue)
            right_view.append(queue[-1].val)  # 1.将每一层的最后元素放入right_view结果集中
            while level_size > 0:
                temp = queue.popleft()
                if temp.left:
                    queue.append(temp.left)
                if temp.right:
                    queue.append(temp.right)
                level_size -= 1
        return right_view   # 2.返回结果集即可

第七题:路径总和

Leetcode112:路径总和:简单题 (详情点击链接见原题)

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

BFS 使用队列保存遍历到每个节点时的路径和,如果该节点恰好时叶子节点,并且路径和正好等于targetSum说明找到了解
python完整题解代码

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        queue = deque()
        queue.append((root, root.val))  # 队列中采用二元组保存节点和节点的值
        while queue:
            temp_node, temp_value = queue.popleft()
            if not temp_node.left and not temp_node.right:
                if temp_value == targetSum:
                    return True
            if temp_node.left:
                queue.append((temp_node.left, temp_value + temp_node.left.val))
            if temp_node.right:
                queue.append((temp_node.right, temp_value + temp_node.right.val))
        return False

第八题:最大层内元素和

Leetcode1161. 最大层内元素和:中等题 (详情点击链接见原题)

给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推

python完整题解代码

class Solution:
    def maxLevelSum(self, root: Optional[TreeNode]) -> int:
        queue = deque()
        queue.append(root)
        min_level_sum = -sys.maxsize   # 记录最小的层级元素和
        level = 1   # 记录当前遍历的层级
        ans = 0    # # 记录最小的层级元素和的层级号
        while queue:
            size = len(queue)
            level_sum = 0   # 记录当前层级的所有元素和
            while size > 0:
                node = queue.popleft()
                level_sum += node.val
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
                size -= 1

            if min_level_sum < level_sum:
                min_level_sum = level_sum
                ans = level
            level += 1
        return ans

二、网格(矩阵)中的BFS

2.1 多源BFS问题

第一题:地图分析

Leetcode1162. 地图分析:中等题 (详情点击链接见原题)

你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 01 标记好了。其中 0 代表海洋,1 代表陆地

解题思路
相信大家对树的 BFS 已经驾轻就熟,先把 root 节点入队,然后再一层一层的无脑遍历就行了
对于图的 BFS 也是一样的,区别在于

  1. tree 只有一个 root,而图可以有多个源点,所以首先需要把多个源点都入队
  2. tree 是有向的因此不需要标志是否访问过,而对于无向图来说,必须得标记是否访问过,并且为了防止某个节点多次入队,需要在入队之前就将其设置成已访问

我们只要先把所有的陆地都入队,然后从各个陆地同时开始一层一层的向海洋扩散,那么到最后扩散到的海洋就是最远的海洋
在这里插入图片描述
这道题的绕的地方在于题中说找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,你可以想象成你从每个陆地上派了很多只船去开辟航道,每当船到了新的海洋就会分裂新的船往不同方向去行驶,如果船到达了某个未访问过的海洋,很明显,这么多船最后访问到的海洋肯定是离陆地最远的海洋

python完整题解代码

from collections import deque


class Solution:
    def maxDistance(self, grid: List[List[int]]) -> int:
        queue = deque()
        n = len(grid)
        for x in range(0, n):
            for y in range(0, n):
                if grid[x][y] == 1:  # 把所有的陆地先入队
                    grid[x][y] = 2  # 将陆地结点标记为已访问
                    queue.append([x, y])
        if len(queue) == n * n or len(queue) == 0:  # 如果网格上只有陆地或者只有海洋,返回-1
            return -1

        distance = 0
        while queue:
            size = len(queue)
            while size > 0:
                r, c = queue.popleft()
                for i, j in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
                    if 0 <= i < n and 0 <= j < n and grid[i][j] != 2:
                        grid[i][j] = 2
                        queue.append([i, j])
                size -= 1
            distance += 1
        return distance - 1
第二题:01 矩阵

Leetcode542.01 矩阵:中等题 (详情点击链接见原题)

给定一个由 01 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离

python完整题解代码

from collections import deque


class Solution:
    def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
        row, col = len(mat), len(mat[0])
        ans = [[0 for _ in range(col)] for _ in range(row)]
        visited = [[False for _ in range(col)] for _ in range(row)]
        queue = deque()
        for x in range(row):
            for y in range(col):
                if mat[x][y] == 0:
                    queue.append((x, y))
                    visited[x][y] = True

        step = 0
        while queue:
            n = len(queue)

            while n > 0:
                x, y = queue.popleft()
                if mat[x][y] == 1:
                    ans[x][y] = step
                for r, c in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:
                    if 0 <= r < len(mat) and 0 <= c < len(mat[0]) and not visited[r][c]:
                        queue.append((r, c))
                        visited[r][c] = True
                n -= 1
            step += 1
        return ans
第三题:腐烂的橘子

Leetcode994. 腐烂的橘子:中等题 (详情点击链接见原题)

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:
0 代表空单元格;
1 代表新鲜橘子;
2 代表腐烂的橘子

python完整题解代码

from collections import deque


class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        row, col = len(grid), len(grid[0])
        queue = deque()
        fresh_orange_count = 0
        for x in range(0, row):
            for y in range(0, col):
                if grid[x][y] == 2:  # 遇到坏橘子先入队列
                    queue.append((x, y))
                elif grid[x][y] == 1:   # 记录新鲜橘子的数量
                    fresh_orange_count += 1
        min_minute = 0   # 记录所需的最少分钟数
        while fresh_orange_count > 0 and queue:  # 加入数量条件是为了防止最后多循环一轮(不用等到扩散整个网格,只要没有新鲜橘子就返回结果)
            n = len(queue)  # 获取当前层的坏橘子数
            while n > 0:
                row, col = queue.popleft()
                for r, c in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
                    if 0 <= r < len(grid) and 0 <= c < len(grid[0]) and grid[r][c] == 1:
                        grid[r][c] = 2   # 橘子腐烂(等价于标记为已访问)
                        fresh_orange_count -= 1   # 新鲜橘子的数量-1
                        queue.append((r, c))
                n -= 1
            min_minute += 1
        return -1 if fresh_orange_count > 0 else min_minute
第四题:迷宫中离入口最近的出口

Leetcode1926. 迷宫中离入口最近的出口:中等题 (详情点击链接见原题)

给你一个 m x n 的迷宫矩阵 maze (下标从 0 开始),矩阵中有空格子(用 '.' 表示)和墙(用 '+' 表示)。同时给你迷宫的入口 entrance ,用 entrance = [entrancerow, entrancecol] 表示你一开始所在格子的行和列

多源BFS问题
逆向思维,即从出口出发,看最快到达出发点的路径,起始时,将所有出口点坐标入队

python完整题解代码

from collections import deque


class Solution:
    def bfs(self, maze, queue, entrance):
        shortest_len = 1
        while queue:
            n = len(queue)
            while n > 0:
                x, y = queue.popleft()
                if x == entrance[0] and y == entrance[1]:
                    return shortest_len
                for i, j in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:
                    if 0 <= i < len(maze) and 0 <= j < len(maze[0]) and maze[i][j] == '.':
                        maze[i][j] = '*'  # 标记为已访问
                        queue.append((i, j))
                n -= 1
            shortest_len += 1
        return -1

    def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int:
        row, col = len(maze), len(maze[0])
        queue = deque()
        for r in range(0, row):
            for c in range(0, col):
                if r == 0 or r == row - 1 or c == 0 or c == col - 1:
                    if maze[r][c] == '.' and entrance != [r, c] and [r, c] not in queue:
                        queue.append([r, c])

        if not queue:  # 没有出口返回-1
            return -1
        min_dis = self.bfs(maze, queue, entrance)
        return min_dis


if __name__ == '__main__':
    s = Solution()
    maze = [["+", "+", ".", "+"], [".", ".", ".", "+"], ["+", "+", "+", "."]]
    entrance = [1, 2]
    print(s.nearestExit(maze, entrance))

三、图中的BFS

3.1 拓扑排序问题

第一题:课程表(有向无环图DAG)

Leetcode207. 课程表:中等题 (详情点击链接见原题)

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi

  • 一共有n门课要上,编号为0 ~ n - 1
  • 先决条件 [1, 0],意思是必须先上课 0,才能上课 1
  • 给你n和一个先决条件表,请你判断能否完成所有课程

n = 6, 先决条件表:[[3, 0],[3, 1],[4, 1],[4, 2],[5, 3], [5, 4]],课0, 1, 2没有先修课,可以直接选,其余的课都有两门先修课
用有向无环图描述依赖关系
在这里插入图片描述
这种叫有向无环图,把一个有向无环图转成线性的排序叫拓扑排序,图中顶点 0, 1, 2的入度为0,顶点3, 4, 5的入度为2

使用BFS前的准备工作

  1. 每门课的入度需要被记录
  2. 课程之间的依赖关系也要被记录,我们关心选当前课会减小哪些课的入度
  3. 保存上面数据信息【每门课的入度,课程之间的依赖关系】需要选择何时的数据结构
  • 入度数组:课程0~n-1作为索引,通过遍历先决条件表求出对应的初始入度
  • 邻接表:用哈希表记录依赖关系(key:课程号,value:依赖这门课的后续课)

使用BFS

  1. 让入度为 0 的课程入列,他们是能直接选的课
  2. 让入度为 0 的课程逐个出列,出列代表着课被选,需要减小和该课程相关课的入度
  3. 如果相关课的入度变为 0,将该课程入队,再出队直到没有入度为 0 的课程入队

怎么判断能够修完所有课

  1. BFS结束时,如果仍有课的入度不为0,说明完成不了所有课
  2. 用一个变量count记录入列的顶点个数,最后判断 count 是否等于总课程数

python完整题解代码

from collections import deque, defaultdict


class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        indegrees = [0] * numCourses  # 记录每门课程节点的入度
        adj_table = defaultdict(list)  # key:课程号0, value:依赖这门课的后续课
        queue = deque()

        for cur, pre in prerequisites:  # 1.统计入度和邻接表
            indegrees[cur] += 1
            adj_table[pre].append(cur)

        for i in range(numCourses):  # 2.将入度为 0 的节点入队
            if indegrees[i] == 0:
                queue.append(i)
        while queue:
            cur = queue.popleft()  # 3. 队首节点出队
            numCourses -= 1
            for cur_node in adj_table[cur]:  # 4.找到和该课程节点相关的后续课程
                indegrees[cur_node] -= 1    # 5.将相关后续课程节点的入度-1
                if indegrees[cur_node] == 0:  # 6.如果入度为 0 表示该课程的节点的先修课程都已修完,将该节点入队表示可休该课程
                    queue.append(cur_node)
        return numCourses == 0   # 7.判断是否修完所有课程

注意defaultdictpython 内建 dict 类的一个字类,功能与dict 相同,但它带有一个默认的值,若key 值不存在时返回一个默认的值

第二题:课程表 II

Leetcode210. 课程表 II:中等题 (详情点击链接见原题)

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi

python完整题解代码

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        indegrees = [0] * numCourses  # 记录每门课程节点的入度
        adj_table = defaultdict(list)  # key:课程号0, value:依赖这门课的后续课
        queue = deque()

        completed_course = []

        for cur, pre in prerequisites:  # 1.统计入度和邻接表
            indegrees[cur] += 1
            adj_table[pre].append(cur)

        for i in range(numCourses):  # 2.将入度为 0 的节点入队
            if indegrees[i] == 0:
                queue.append(i)
        while queue:
            cur = queue.popleft()  # 3. 队首节点出队
            completed_course.append(cur)
            numCourses -= 1
            for cur_node in adj_table[cur]:  # 4.找到和该课程节点相关的后续课程
                indegrees[cur_node] -= 1  # 5.将相关后续课程节点的入度-1
                if indegrees[cur_node] == 0:  # 6.如果入度为 0 表示该课程的节点的先修课程都已修完,将该节点入队表示可休该课程
                    queue.append(cur_node)

        if numCourses == 0:  # 7.判断是否修完所有课程
            return completed_course
        else:
            return []

3.2 其他问题

第一题: 省份数量

Leetcode547. 省份数量:中等题 (详情点击链接见原题)

n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连

python完整题解代码

from collections import deque

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        n = len(isConnected)   # isConnected是无向图的邻接矩阵,n为无向图的顶点数量
        visited = [False] * n   # 用来标识图中结点是否已经被访问
        count = 0   # count 用来累计遍历过的连通域的数量
        queue = deque()
        for i in range(n):
            if not visited[i]:
                # 若当前顶点 i 未被访问,说明又是一个新的连通域,则bfs新的连通域且cnt+=1
                count += 1
                queue.append(i)
                visited[i] = True    # 将当前结点标记为已访问
                while queue:
                    v = queue.popleft()   # 弹出当前结点
                    for j in range(n):
                        if isConnected[v][j] == 1 and not visited[j]:
                            visited[j] = True
                            queue.append(j)
        return count

三、经典案例:岛屿问题中的BFS

第一题:岛屿数量

Leetcode200. 岛屿数量:中等题 (详情点击链接见原题)

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量

python完整题解代码

from collections import deque


class Solution:
    def bfs(self, grid, x, y):
        grid[x][y] = '2'
        queue = deque()
        queue.append((x, y))
        while queue:
            row, col = queue.popleft()
            for i, j in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
                if 0 <= i < len(grid) and 0 <= j < len(grid[0]) and grid[i][j] == '1':
                    grid[i][j] = '2'
                    queue.append((i, j))

    def numIslands(self, grid: List[List[str]]) -> int:
        row, col = len(grid), len(grid[0])
        nums_island = 0
        for x in range(0, row):
            for y in range(0, col):
                if grid[x][y] == '1':
                    nums_island += 1    # 岛屿的数量就是进行广度优先搜索的次数
                    self.bfs(grid, x, y)
        return nums_island

第二题:岛屿的最大面积

Leetcode695. 岛屿的最大面积:中等题 (详情点击链接见原题)

给你一个大小为 m x n 的二进制矩阵 grid
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着

python完整题解代码

class Solution:
    def bfs(self, grid, x, y):
        area = 1
        queue = deque()
        queue.append([x, y])
        grid[x][y] = 2   # 标记为已访问
        while queue:
            r, c = queue.popleft()
            for i, j in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
                if 0 <= i < len(grid) and 0 <= j < len(grid[0]) and grid[i][j] == 1:
                    grid[i][j] = 2  # 标记为已访问过
                    queue.append([i, j])  # 加入队列
                    area += 1
        return area

    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        max_area = 0
        row, col = len(grid), len(grid[0])
        for x in range(0, row):
            for y in range(0, col):
                if grid[x][y] == 1:
                    # max_area += self.bfs(grid, x, y)
                    max_area = max(max_area, self.bfs(grid, x, y))
        return max_area

第三题:衣橱整理

LCR 130. 衣橱整理:中等题 (详情点击链接见原题)

家居整理师将待整理衣橱划分为 m x n 的二维矩阵 grid,其中 grid[i][j] 代表一个需要整理的格子。整理师自 grid[0][0] 开始 逐行逐列 地整理每个格子

python完整题解代码

from collections import deque


class Solution:
    def BitSum(self, num):
        res = 0
        while num > 0:
            bit = num % 10
            res += bit
            num //= 10
        return res

    def wardrobeFinishing(self, m: int, n: int, cnt: int) -> int:
        grid = [[0 for _ in range(n)] for _ in range(m)]  # 1.初始化整个网格
        queue = deque()
        queue.append([0, 0]) # 1.将源点加入队列queue
        grid[0][0] = 1   # 2.将源点标记为已访问
        count = 0    # count 用来统计需要整理的格子的数量
        while queue:  # 迭代终止条件,队列为空
            x, y = queue.popleft()
            count += 1	# 3.每弹出一个需要打扫的单元格,count + 1
            for r, c in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:
                if 0 <= r < m and 0 <= c < n and grid[r][c] == 0 and self.BitSum(r) + self.BitSum(c) <= cnt:  # 4.对当前网格的上下左右的四个网格依次遍历判断是否需要跳过
                    queue.append([r, c])  # 5.将需要整理的单元格入队
                    grid[r][c] = 1      # 6.将该单元格标记为已访问
        return count	# 6.返回最终需要整理的网格数量

第四题:太平洋大西洋水流问题

Leetcode417. 太平洋大西洋水流问题:中等题 (详情点击链接见原题)

有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界

四、字符串变换问题

第一题:最小基因变化

Leetcode433. 最小基因变化:中等题 (详情点击链接见原题)

基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 'A'、'C'、'G''T' 之一

python题解代码

class Solution:
    def minMutation(self, startGene: str, endGene: str, bank: List[str]) -> int:
        queue = deque()
        queue.append((startGene, 0))
        while queue:
            n = len(queue)
            while n > 0:   # 对当前层
                gene, step = queue.popleft()
                if gene == endGene:   # 如果搜索到 endGene 直接返回当前的步数
                    return step
                for i in range(len(gene)):
                    for x in "ACGT":  # 对当前字符串中的每个字符都转变成 ACGT 四个字符,看新形成的字符串是否遇到过
                        newGene = gene[:i] + x + gene[i + 1:]
                        if newGene in bank and newGene != gene:   # 如果没遇到过就放入队列之中
                            queue.append((newGene, step + 1))
                            bank.remove(newGene)   # 从bank中删除已经遇到过的字符串
                n -= 1
        return -1
第二题:单词接龙

Leetcode127. 单词接龙:困难题 (详情点击链接见原题)

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

python完整题解代码

from collections import deque


class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        word_set = set(wordList)
        if len(word_set) == 0 or endWord not in word_set:
            return 0

        if beginWord in word_set:   # 题目说明 beginWord 不需要在 wordList 中
            word_set.remove(beginWord)

        queue = deque()
        queue.append((beginWord, 1))   # 题目求的时序列所以初始step从1开始

        while queue:
            size = len(queue)
            while size > 0:
                word, step = queue.popleft()
                if word == endWord:
                    return step
                word_list = list(word)
                for j in range(len(word)):
                    origin_char = word_list[j]
                    for k in range(26):
                        word_list[j] = chr(ord('a') + k)
                        next_word = ''.join(word_list)
                        if next_word in word_set and next_word != word:
                            queue.append((next_word, step + 1))
                            word_set.remove(next_word)
                    word_list[j] = origin_char
                size -= 1
        return 0


if __name__ == '__main__':
    beginWord = "hit"
    endWord = "cog"
    wordList = ["hot", "dot", "dog", "lot", "log", "cog"]
    solution = Solution()
    res = solution.ladderLength(beginWord, endWord, wordList)
    print(res)

五、其他问题

第一题:钥匙和房间

Leetcode841. 钥匙和房间:中等题 (详情点击链接见原题)

n 个房间,房间按从 0n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间

python完整题解代码

from collections import deque


class Solution:
    def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
        n = len(rooms)
        visited = [False] * n  # 1.visited数组用于标记房间是否被访问过
        visited[0] = True   # 2.从0号房间开始
        queue = deque()
        queue.append(rooms[0])
        while queue:    # 3.广度优先搜索的过程
            room = queue.popleft()
            for r in room:
                if not visited[r]:
                    visited[r] = True
                    queue.append(rooms[r])
        for v in visited:  # 4.检查房间是不是都遍历过了
            if not v:
                return False
        return True

五、总结

本文给大家介绍了广度优先搜索算法(BFS:Breath First Search),以及相关的题型,相较于DFSBFS 要简单一些,树的BFS和图的BFS有比较大的区别,其中的图的BFS中需要注意源点时单源BFS还是多源BFS,本文的介绍就到这里~

  • 23
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code_lover_forever

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值