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. 相同的树:简单题 (详情点击链接见原题)
给你两棵二叉树的根节点
p
和q
,编写一个函数来检验这两棵树是否相同
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
,上面的每个 单元格 都用0
和1
标记好了。其中0
代表海洋,1
代表陆地
解题思路
相信大家对树的 BFS
已经驾轻就熟,先把 root
节点入队,然后再一层一层的无脑遍历就行了
对于图的 BFS
也是一样的,区别在于
tree
只有一个root
,而图可以有多个源点,所以首先需要把多个源点都入队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 矩阵:中等题 (详情点击链接见原题)
给定一个由
0
和1
组成的矩阵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
门课程,记为0
到numCourses - 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前的准备工作
- 每门课的入度需要被记录
- 课程之间的依赖关系也要被记录,我们关心选当前课会减小哪些课的入度
- 保存上面数据信息【每门课的入度,课程之间的依赖关系】需要选择何时的数据结构
- 入度数组:课程
0~n-1
作为索引,通过遍历先决条件表求出对应的初始入度 - 邻接表:用哈希表记录依赖关系(
key
:课程号,value
:依赖这门课的后续课)
使用BFS
- 让入度为
0
的课程入列,他们是能直接选的课 - 让入度为
0
的课程逐个出列,出列代表着课被选,需要减小和该课程相关课的入度 - 如果相关课的入度变为
0
,将该课程入队,再出队直到没有入度为0
的课程入队
怎么判断能够修完所有课
BFS
结束时,如果仍有课的入度不为0
,说明完成不了所有课- 用一个变量
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.判断是否修完所有课程
注意:defaultdict
是 python
内建 dict
类的一个字类,功能与dict
相同,但它带有一个默认的值,若key
值不存在时返回一个默认的值
第二题:课程表 II
Leetcode210. 课程表 II:中等题 (详情点击链接见原题)
你这个学期必须选修
numCourses
门课程,记为0
到numCourses - 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
中从单词beginWord
和endWord
的 转换序列 是一个按下述规格形成的序列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
个房间,房间按从0
到n - 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)
,以及相关的题型,相较于DFS
,BFS
要简单一些,树的BFS
和图的BFS
有比较大的区别,其中的图的BFS
中需要注意源点时单源BFS
还是多源BFS
,本文的介绍就到这里~