初识广度优先搜索(BFS):从 LeetCode 三道题领会精髓
2024-01-12 22:49:35
我们已经领略了深度优先搜索(DFS)的奥妙,今天,让我们将目光投向另一个强大的搜索算法——广度优先搜索(BFS)。同样通过三道 LeetCode 习题,我们将逐层揭开 BFS 的神秘面纱。
广度优先搜索简介
广度优先搜索是一种以队列数据结构为基础的遍历算法,它的核心思想是先访问当前节点的相邻节点,然后再访问相邻节点的相邻节点,以此类推,层层推进。与 DFS 不同,BFS 始终沿着同一层进行探索,直到该层的所有节点都被访问完毕,然后再继续下一层的探索。
LeetCode 习题 1:判断岛屿数量
我们从 LeetCode 中最经典的岛屿问题入手,理解 BFS 的基本原理。
给定一个由 '1'(陆地)和 '0'(水域)组成的二维网格,计算岛屿的数量。一个岛屿被定义为一块被水域包围的相邻陆地区域。
def num_islands(grid):
if not grid:
return 0
rows, cols = len(grid), len(grid[0])
num_islands = 0
for i in range(rows):
for j in range(cols):
if grid[i][j] == '1':
num_islands += 1
bfs(grid, i, j)
return num_islands
def bfs(grid, i, j):
if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] == '0':
return
grid[i][j] = '0' # 标记已访问
# 访问相邻节点
bfs(grid, i+1, j) # 向下
bfs(grid, i-1, j) # 向上
bfs(grid, i, j+1) # 向右
bfs(grid, i, j-1) # 向左
BFS 算法首先将网格中标记为 '1' 的陆地区域作为起始节点,然后将其入队。接下来,BFS 从队列中取出当前节点,并访问其所有相邻的 '1' 陆地区域,并将其入队。此过程一直持续到队列为空,表明当前层的所有节点均已访问完毕。
LeetCode 习题 2:计算矩阵中的最长路径
下一个习题让我们深入了解 BFS 在图论中的应用。
给定一个由 '0'(空地)和 '1'(障碍)组成的矩阵,找出机器人从左上角移动到右下角的最长路径长度。机器人每次只能向右或向下移动一步。
def longest_path(matrix):
if not matrix:
return 0
rows, cols = len(matrix), len(matrix[0])
dp = [[0] * cols for _ in range(rows)]
# 初始化第一行和第一列
for i in range(rows):
dp[i][0] = matrix[i][0]
for j in range(cols):
dp[0][j] = matrix[0][j]
# 动态规划计算最长路径
for i in range(1, rows):
for j in range(1, cols):
if matrix[i][j] == '0':
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + 1
return dp[rows-1][cols-1]
在此问题中,我们将矩阵视作一个图,其中 '0' 陆地区域表示可以通行的路径,而 '1' 障碍表示不可通行的障碍物。BFS 算法通过层层推进的方式,从左上角出发,逐渐探索矩阵中可行的路径,并记录路径长度。
LeetCode 习题 3:查找单词
最后一道习题将展示 BFS 在单词查找中的妙用。
给定一个二维字符网格和一个单词,找出该单词是否出现在网格中。单词可以由网格中的字母组成,每次只能移动相邻的单元格一次。
def word_search(board, word):
if not board or not word:
return False
rows, cols = len(board), len(board[0])
for i in range(rows):
for j in range(cols):
if board[i][j] == word[0]:
if dfs(board, word, i, j, 0):
return True
return False
def dfs(board, word, i, j, index):
if index == len(word):
return True
if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or board[i][j] != word[index]:
return False
temp, board[i][j] = board[i][j], '/' # 标记已访问
# 访问相邻节点
found = (dfs(board, word, i+1, j, index+1) or
dfs(board, word, i-1, j, index+1) or
dfs(board, word, i, j+1, index+1) or
dfs(board, word, i, j-1, index+1))
board[i][j] = temp # 恢复原值
return found
对于单词查找问题,BFS 通过从网格中每个可能的位置出发,逐层探索单词的字母是否存在相邻单元格中。一旦找到一个匹配的字母,BFS 就继续搜索下一个字母,直到单词的所有字母都找到或搜索失败为止。
结语
通过这三道 LeetCode 习题,我们深入理解了广度优先搜索(BFS)算法的基本原理和图论中的应用场景。从队列数据结构的巧妙运用到层层推进的搜索方式,BFS 为解决图论问题提供了高效且直观的解决方案。希望这篇文章能为各位探索图论算法的世界打开一扇大门。