【C++】【leetcode200】岛屿数量(DFS、BFS)代码优化

这篇博客介绍了如何利用深度优先搜索(DFS)和广度优先搜索(BFS)来解决计算二维网格中连通岛屿数量的问题。通过修改网格中的值来避免重复访问,同时展示了两种不同的实现方式,以及代码的优化,如使用偏移量数组提高效率。

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

岛屿数量
在这里插入图片描述

DFS

class Solution {
public:
    int n,m;
    void dfs(vector<vector<char>>& grid, vector<vector<int>>& visited,int i,int j) {
        if(i < 0 || i > m - 1 || j < 0 || j > n - 1 || grid[i][j] == '0')return;
        visited[i][j] = 1;
        if(i - 1 >= 0 && !visited[i - 1][j]) dfs(grid,visited,i - 1,j);
        if(i + 1 < m && !visited[i + 1][j])  dfs(grid,visited,i + 1,j);
        if(j - 1 >= 0 && !visited[i][j - 1]) dfs(grid,visited,i,j - 1);
        if(j + 1 < n && !visited[i][j + 1]) dfs(grid,visited,i,j + 1);
    }
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size();
        n = grid[0].size();
        int ans = 0;
        vector<vector<int>> visited(m,vector<int>(n));

        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(grid[i][j] == '1' && !visited[i][j]){
                    ++ans;
                    dfs(grid,visited,i,j);
                }
            }
        }
        return ans;
    }
};

BFS

  • 不用定义访问数组,被访问过的直接把值改掉就好了
class Solution {
public:
    //BFS求解
    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        queue<pair<int,int>> q;
        int ans = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    q.push({i,j});
                    grid[i][j] = '0';
                    while (!q.empty()) {
                        auto rc = q.front();
                        int row = rc.first, col = rc.second;
                        q.pop();
                        if (row+1 <= m-1 && grid[row+1][col] == '1' ){
                            grid[row+1][col] = '0';
                            q.push({row+1,col});
                        }
                        if (col+1 <= n-1 && grid[row][col + 1] == '1'){
                            grid[row][col+1] = '0';
                            q.push({row,col+1});
                        }
                        if (col-1 >= 0 && grid[row][col - 1] == '1' ){
                            grid[row][col-1] = '0';
                            q.push({row,col-1});
                        }
                        if (row-1 >= 0 && grid[row - 1][col ] == '1'){
                            grid[row-1][col] = '0';
                            q.push({row-1,col});
                        }
                    }
                    ++ans;
                }
            }
        }
        return ans;
    }
};

省份数量

代码改进

使用偏移量数组

class Solution {
public:
    int n,m;
    const int dr[4] = {-1,1,0,0};
    const int dc[4] = {0,0,-1,1};
    void dfs(vector<vector<char>>& grid,int r,int c){
        grid[r][c] = 'A';
        for(int i = 0;i < 4;++i){
            int rr = r + dr[i];
            int cc = c + dc[i];
            if(rr < 0 || cc < 0 || rr >= n || cc >= m || grid[rr][cc] != '1')continue;
            dfs(grid,rr,cc);
        }
    }
    int numIslands(vector<vector<char>>& grid) {
        n = grid.size();
        m = grid[0].size();
        int ans = 0;
        for(int i = 0;i < n;++i){
            for(int j = 0;j < m;++j){
                if(grid[i][j] != '1')continue;
                dfs(grid,i,j);
                ++ans;
            }
        }
        return ans;
    }
};
<think>好的,我现在需要介绍DFSBFSC++常见模板以及对应的经典习题。首先,我得回忆一下DFSBFS的基本概念和应用场景。DFS是深度优先搜索,用栈或递归实现,适合解决路径问题、连通性问题等;而BFS是广度优先搜索,用队列实现,适合最短路径、层次遍历等问题。 接下来,我需要整理它们的常见模板。对于DFS,递归模板比较常见,比如处理二叉树遍历或者图的遍历。非递归的话,可能需要用显式栈来模拟。BFS通常是用队列实现的,模板相对固定,比如层序遍历二叉树或者找最短路径。 然后,学习阶段的经典习题要分难度。基础阶段可能包括二叉树的遍历、岛屿问题等。进阶的话可能有拓扑排序、双向BFS等。每个阶段要举几个例子,并说明对应的LeetCode题号,方便学习者练习。 需要注意模板的正确性,比如递归的终止条件,BFS的访问标记等。同时,要提醒读者注意栈溢出问题,或者BFS的内存消耗。另外,模板的适用场景也需要解释清楚,避免误用。 可能还需要对比DFSBFS的区别,比如DFS适合寻找所有解,而BFS适合找最短路径。这有助于读者根据问题选择合适的算法。 最后,要检查模板的代码是否正确,比如递归参数是否传递正确,队列的操作是否标准,防止出现常见的错误,比如忘记标记已访问节点导致死循环。</think>### DFS & BFS C++ 模板与经典习题指南 --- #### 一、DFS 深度优先搜索 **核心特点**:递归/栈结构、单路径深入、回溯思想 **时间复杂度**:一般为 $O(n)$ 或 $O(2^n)$(全排列类问题) ##### 1. 递归模板(二叉树遍历) ```cpp void dfs(TreeNode* root) { if (!root) return; // 终止条件 // 前序遍历操作(在此处理当前节点) dfs(root->left); // 递归左子树 // 中序遍历操作 dfs(root->right); // 递归右子树 // 后序遍历操作 } ``` **经典习题**: - 基础:二叉树遍历(LeetCode 144/94/145) - 进阶:路径总和(LeetCode 112)、二叉树剪枝(LeetCode 814) ##### 2. 回溯模板(组合/排列问题) ```cpp vector<vector<int>> res; vector<int> path; void backtrack(参数) { if (终止条件) { res.push_back(path); return; } for (选择 : 本层集合) { path.push_back(选择); // 记录路径 backtrack(新参数); // 递归 path.pop_back(); // 撤销选择(回溯) } } ``` **经典习题**: - 全排列(LeetCode 46) - 子集(LeetCode 78) - N皇后问题(LeetCode 51) --- #### 二、BFS 广度优先搜索 **核心特点**:队列结构、层序遍历、最短路径 **时间复杂度**:一般为 $O(n)$ ##### 1. 基础模板(层序遍历) ```cpp void bfs(TreeNode* root) { queue<TreeNode*> q; q.push(root); while (!q.empty()) { int size = q.size(); for (int i = 0; i < size; ++i) { // 处理当前层 auto node = q.front(); q.pop(); // 处理当前节点 if (node->left) q.push(node->left); if (node->right) q.push(node->right); } } } ``` **经典习题**: - 二叉树层序遍历(LeetCode 102) - 迷宫最短路径(LeetCode 490) ##### 2. 多源BFS模板 ```cpp // 适用于多起点同时扩散的场景 queue<pair<int,int>> q; for (所有起点) q.push({x,y}); while (!q.empty()) { auto [x,y] = q.front(); q.pop(); for (四个方向) { int nx = x + dx[i], ny = y + dy[i]; if (越界或不符合条件) continue; // 更新状态并加入队列 } } ``` **经典习题**: - 腐烂的橘子(LeetCode 994) - 地图分析(LeetCode 1162) --- #### 三、学习路线建议 | 学习阶段 | 推荐习题 | 核心训练目标 | |---------|---------|-------------| | **入门** | 二叉树遍历(DFS/BFS) | 掌握基础递归与队列操作 | | **基础** | 岛屿问题(LeetCode 200) | 理解连通性问题处理 | | **进阶** | 单词接龙(LeetCode 127) | 掌握双向BFS优化 | | **高手** | 滑动谜题(LeetCode 773) | 状态压缩与复杂BFS | --- #### 四、算法选择技巧 1. **优先BFS**:求最短路径、最小步数问题 2. **优先DFS**:要求所有可能解、连通性检测问题 3. **双向BFS**:当起点终点明确且层级较深时使用 4. **记忆化DFS**:存在重复子问题时(如 LeetCode 329) **注意事项**: - DFS注意栈溢出(递归深度超过 $10^4$ 时改用迭代) - BFS注意空间消耗(使用层级计数优化内存)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值