【LeetCode】一文吃透搜索算法(DFS | BFS | 附例题)

本文深入介绍了深度优先搜索(DFS)和广度优先搜索(BFS)这两种搜索算法,包括它们的概念、模板示例以及在网格问题和岛屿计数等场景中的应用。同时,文章讨论了在DFS中如何处理网格问题,以及BFS的队列实现方式,并列举了相关问题和经典案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深度优先搜索和宽度优先搜索算法深入浅出,一文吃透!

原文地址:https://github.com/EricPengShuai/Interview/blob/main/algorithm/搜索算法.md

搜索算法

0. 概念

搜索算法主要是 深度优先搜索 和 广度优先搜索:

深度优先搜索 算法(英文:Depth-First-Search,DFS)是一种用于 遍历或搜索树或图 的算法。这个算法会 尽可能深 的搜索树的分支。当结点 v 的所在边都己被探寻过,搜索将 回溯 到发现结点 v 的那条边的起始结点。这一过程一直进行到已发现从源结点可达的所有结点为止。如果还存在未被发现的结点,则选择其中一个作为源结点并重复以上过程,整个进程反复进行直到所有结点都被访问为止。

回溯经常使用 DFS 实现,两者之间有着千丝万缕的联系,具体可以看看 回溯算法

广度优先搜索 算法(英语:Breadth-First Search,缩写为BFS),又叫宽度优先搜索,或横向优先搜索,是一种图形搜索演算法。简单的说,BFS 是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。广度优先搜索的实现一般采用open-closed表。

1. 模板

二叉树路径问题 那篇文章已经给出了典型的 DFS/BFS 模板,不过那个主要是针对二叉树的,这里我们主要关注 网格问题 或者 岛屿问题,典型题目就是 200. 岛屿数量

1.1 DFS

DFS 一般使用递归实现,二叉树的 DFS 有两个要素:

访问相邻节点:二叉树的相邻节点就是左右子节点,递归左右子树即可

判断 base case:二叉树的 base case 一般是root == nullptr

网格的 DFS 问题可以参照二叉树的 DFS 总结如下要素:

访问相邻格子:网格的“相邻节点”就是上下左右四个格子,可以理解为“四叉树”

判断 base case:类似二叉树,网络 base case 就是判断格子是否越界

// 网格 DFS 模板
void dfs(vector<vector<int>>& grid, int r, int c) {
    // 判断 base case
    // 如果坐标 (r, c) 超出了网格范围,直接返回
    if (r < 0 || r >= grid.size() || c < 0 || c >= grid[0].size()) {
        return;
    }
    
    // 如果格子不是不是“陆地”直接返回
    if (grid[r][c] != 1) {
        return;
    }
    
    // 标记已经遍历过的“陆地格子”
    grid[r][c] = 2;
    
    // 访问上、下、左、右四个相邻结点
    dfs(grid, r - 1, c);
    dfs(grid, r + 1, c);
    dfs(grid, r, c - 1);
    dfs(grid, r, c + 1);
}

在一些题解中,可能会把「已遍历过的陆地格子」标记为和海洋格子一样的 0,美其名曰「陆地沉没方法」,即遍历完一个陆地格子就让陆地「沉没」为海洋。这种方法看似很巧妙,但实际上有很大隐患,因为这样我们就**无法区分「海洋格子」和「已遍历过的陆地格子」**了。如果题目更复杂一点,这很容易出 bug。

1.2 BFS

BFS 一般使用 队列 实现,二叉树的 BFS 一般用队列维护根节点:

① 队列不空条件下维护根节点

② 如果左右节点不为空就入队处理

类似地,对于网格问题也就是处理格子坐标:

队列中基本元素:队列不空条件下维护当前网格坐标

边界条件:如果格子是没有遍历过的并且未出界就入队处理上下左右四个及诶单

void bfs(vector<vector<int>>& grid, int r, int c) {
    queue<pair<int, int>> qu;
    qu.push({r, c});
    while (!qu.empty()) {
        auto [i, j] = qu.front();
        qu.pop();
        if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) {
            continue;
        }
        if (grid[i][j] != '1') {
            continue;
        }
        grid[i][j] = '2';
        qu.push({i+1, j});
        qu.push({i-1, j});
        qu.push({i, j+1});
        qu.push({i, j-1});
    }
}

2. 相关问题

典型网格

题目说明题解
200. 岛屿数量基础BFS/DFS,遍历过的陆地格子标记为2DFS BFS
695. 岛屿的最大面积和 LC.200 类似,只是求所有岛屿面积的最大值通过
827. 最大人工岛要区分不同岛屿,set记录下标然后统计面积🔥图解
463. 岛屿的周长在 DFS 遍历中,从一个岛屿方格走向一个非岛屿方格,周长就加 1图解
  • 先污染后治理:先处理上下左右四个格子,然后判断边界条件

非典型网格

题目说明题解
547. 省份数量连通分量个数,典型的并查集,另外 DFS/BFS 也可以标记节点DFS BFS
934. 最短的桥BFS/DFS 找岛都可以,最短路径一般使用 BFS,双 DFS 会超时图解
1971. 寻找图中是否存在路径判断节点是否连通,典型并查集,DFS/BFS 需要邻接表建图(无权重)DFS BFS

3. 参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值