【4.4】图搜索算法-BFS和DFS两种方式解岛屿数量

news2024/12/23 23:06:55

一、题目

        给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。

示例 1:
输入:
[
[ '1' , '1' , '1' , '1' , ' 0 ' ] ,
[ '1' , '1' , ' 0 ' , ' 1' , ' 0 ' ] ,
[ '1' , '1' , ' 0 ' , ' 0 ' , ' 0 ' ] ,
[ ' 0 ' , ' 0 ' , ' 0 ' , ' 0 ' , ' 0 ' ]
]
输出: 1


示例 2:
输入:
[
[ '1' , '1' , ' 0 ' , ' 0 ' , ' 0 ' ] ,
[ '1' , '1' , ' 0 ' , ' 0 ' , ' 0 ' ] ,
[ ' 0 ' , ' 0 ' , '1' , ' 0 ' , ' 0 ' ] ,
[ ' 0 ' , ' 0 ' , ' 0 ' , ' 1' , '1' ]
]
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

二、解题思路

DFS解决方式:

        这道题目要求我们计算岛屿的面积,二维数组中值为1的元素表示岛屿。如果多个1是连在一起的,那么它们只能算作一个岛屿。

        最简单的方法是遍历数组中的每一个元素,如果遇到1,说明这是一个岛屿,然后将其置为0(或其他非1的字符),接着遍历其上下左右四个位置。如果这些位置中也有1,说明这些岛屿是相连的,只能算作一个岛屿,我们同样将其置为0,然后再以这些位置为中心,继续遍历它们的上下左右四个位置。如果遇到0,说明这不是岛屿,就不再继续向其上下左右四个位置遍历。以示例1为例:

每个位置只要是1,先要把它置为0,然后沿着他的上下左右4个方向继续遍历,执行同样的操作,要注意边界条件的判断。

BFS解决方式:

        深度优先搜索(DFS)是一种沿着一条路径不断深入的搜索策略,直到遇到终止条件时才会返回。而广度优先搜索(BFS)则是先访问当前位置附近的节点,就像一个不断扩大的圈,先访问圈内的节点,然后再逐步扩大圈的范围继续访问。如下:

这题使用BFS和DFS都能解决,如果遇到位置为1的格子,只要能把他们挨着的为1的全部置为0,然后挨着的挨着的为1的位置也置为0,然后……一直这样循环下去。

三、代码实现

DFS方式:

#include <iostream>
#include <vector>

using namespace std;

void dfs(vector<vector<char>>& grid, int i, int j) {
    // 边界条件判断,不能越界
    if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] == '0')
        return;
    // 把当前格子置为0,然后再从他的上下左右4个方向继续遍历
    grid[i][j] = '0';
    dfs(grid, i - 1, j); // 上
    dfs(grid, i + 1, j); // 下
    dfs(grid, i, j - 1); // 左
    dfs(grid, i, j + 1); // 右
}

int numIslands(vector<vector<char>>& grid) {
    // 边界条件判断
    if (grid.empty() || grid[0].empty())
        return 0;

    int count = 0;

    // 两个for循环遍历每一个格子
    for (int i = 0; i < grid.size(); i++) {
        for (int j = 0; j < grid[0].size(); j++) {
            // 只有当前格子是1才开始计算
            if (grid[i][j] == '1') {
                // 如果当前格子是1,岛屿的数量加1
                count++;
                // 然后通过dfs把当前格子的上下左右4个位置为1的都要置为0,因为他们是连在一起的算一个岛屿
                dfs(grid, i, j);
            }
        }
    }

    // 最后返回岛屿的数量
    return count;
}

int main() {
    vector<vector<char>> grid = {
        {'1', '1', '0', '0', '0'},
        {'1', '1', '0', '0', '0'},
        {'0', '0', '1', '0', '0'},
        {'0', '0', '0', '1', '1'}
    };

    int result = numIslands(grid);
    cout << "Number of islands: " << result << endl;

    return 0;
}

BFS方式:

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

void bfs(vector<vector<char>>& grid, int x, int y) {
    int n = grid.size();
    int m = grid[0].size();
    queue<int> queue;

    // 把当前格子先置为0
    grid[x][y] = '0';
    // 把两位数字转化为一位数字并存放到队列中
    int code = x * m + y;
    queue.push(code);

    while (!queue.empty()) {
        // 出队
        code = queue.front();
        queue.pop();
        // 反转成坐标值(i,j)
        int i = code / m;
        int j = code % m;

        // 上
        if (i > 0 && grid[i - 1][j] == '1') {
            grid[i - 1][j] = '0';
            queue.push((i - 1) * m + j);
        }
        // 下
        if (i < n - 1 && grid[i + 1][j] == '1') {
            grid[i + 1][j] = '0';
            queue.push((i + 1) * m + j);
        }
        // 左
        if (j > 0 && grid[i][j - 1] == '1') {
            grid[i][j - 1] = '0';
            queue.push(i * m + j - 1);
        }
        // 右
        if (j < m - 1 && grid[i][j + 1] == '1') {
            grid[i][j + 1] = '0';
            queue.push(i * m + j + 1);
        }
    }
}

int numIslands(vector<vector<char>>& grid) {
    // 边界条件判断
    if (grid.empty() || grid[0].empty())
        return 0;

    int count = 0;

    // 两个for循环遍历每一个格子
    for (int i = 0; i < grid.size(); i++) {
        for (int j = 0; j < grid[0].size(); j++) {
            // 只有当前格子是1才开始计算
            if (grid[i][j] == '1') {
                // 如果当前格子是1,岛屿的数量加1
                count++;
                // 然后通过bfs把当前格子的上下左右4个位置为1的都要置为0,因为他们是连在一起的算一个岛屿
                bfs(grid, i, j);
            }
        }
    }

    return count;
}

int main() {
    vector<vector<char>> grid = {
        {'1', '1', '0', '0', '0'},
        {'1', '1', '0', '0', '0'},
        {'0', '0', '1', '0', '0'},
        {'0', '0', '0', '1', '1'}
    };

    int result = numIslands(grid);
    cout << "Number of islands: " << result << endl;

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2151686.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

I2C中继器TCA9517A(TI)

一、芯片介绍 本芯片是一款具有电平转换功能的双向缓冲器&#xff0c;适用于I2C和SMBus系统&#xff0c;同时支持各种拓扑结构的扩展使用。芯片支持SCL和SDA缓冲&#xff0c;因此允许两条总线的负载电容达到400pF。 TCA9517A的A和B侧驱动器是不同的&#xff0c;但是均可耐受5…

Obsidian 全部笔记共享配置文件,obsidian仓库-文件夹配置统一化

obsidian仓库-文件夹配置统一化 在每次新建obsidian仓库(vaults)时&#xff0c;仓库的主题和快捷键等都需要重新设置&#xff0c;这是因为每次创建新的仓库时 新仓库的配置文件都是默认配置但是如果通过复制粘贴旧配置文件来达到新仓库的配置和旧仓库一致的话&#xff0c;无法…

kafka3.8的基本操作

Kafka基础理论与常用命令详解&#xff08;超详细&#xff09;_kafka常用命令和解释-CSDN博客 [rootk1 bin]# netstat -tunlp|grep 90 tcp6 0 0 :::9092 :::* LISTEN 14512/java [rootk1 bin]# ./kafka-topics.s…

MVCC机制解析:提升数据库并发性能的关键

MVCC机制解析&#xff1a;提升数据库并发性能的关键 MVCC&#xff08;Multi-Version Concurrency Control&#xff09; 多版本并发控制 。 MVCC只在事务隔离级别为读已提交(Read Committed)和可重复读(Repeated Read)下生效。 MVCC是做什么用的 MVCC是为了处理 可重复读 和…

数据安全治理

数据安全治理 1.数据安全治理2.终端数据安全加密类权限控制类终端DLP类桌面虚拟化安全桌面 3.网络数据安全4.存储数据安全5.应用数据安全6.其他话题数据脱敏水印与溯源 7.UEBA8.CASB 1.数据安全治理 数据安全治理最为重要的是进行数据安全策略和流程制订。在企业或行业内经常发…

酸枣病虫害智能化防控系统的探索与实践,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建枣类作物种植场景下酸枣病虫害智能检测识别系统

智慧农业&#xff0c;作为现代农业的高级形态&#xff0c;通过集成物联网、大数据、人工智能等先进技术&#xff0c;实现了农业生产过程的精准化、智能化管理。在酸枣等经济作物的种植过程中&#xff0c;病虫害的及时监测与防控直接关系到作物的产量与质量&#xff0c;进而影响…

Vue报错 ‘vite‘ 不是内部或外部命令,也不是可运行的程序或批处理文件

报错 vue-project0.0.0 dev vite‘vite’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。解决 第1步. 控制台输入 npm install -g create-vite第2步. 控制台输入 npm install -g vite第3步. 运行就ok啦

伊犁linux 创建yum 源过程

首先要创建yum 源这样后期的服务才能大面积部署 在su 用户下创建 清理缓存&#xff0c;一定要配置 这说明yum安装成功

笔记整理—内核!启动!—kernel部分(8)动态编译链接库与BSP文件

linux的C语言程序是用编译的&#xff0c;但是如果要在开发板上运行的话就不能使用默认的ubuntu提供的gcc编译器&#xff0c;而是使用arm-linux版本的一类的编译器。我们可以用file xx去查看一个程序的架构。 &#xff08;arm架构&#xff09; &#xff08;intel的80386架构&…

Linux命令 —— grep/sed

一、grep命令 grep是Linux中最常用的“文本处理工具”之一&#xff0c;grep与sed、awk合称为Linux中的三剑客。 grep的全称为&#xff1a; Global search Regular Expression and Print out the line 所以&#xff0c;从grep的全称中可以了解到&#xff0c;grep是一个可以利用…

运维开发之堡垒机(Fortress Machine for Operation and Development)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

十种果冻的做法

菠萝果冻 1.在菠萝的1/5处切开&#xff0c;切去顶做盖子用&#xff0c;用水果刀在四周划一圈使皮和果肉分离 2.注意底部切透了&#xff0c;用水果刀把菠萝肉挖出&#xff0c;菠萝肉切丁用盐水浸泡备用 3.把菠萝丁放入料理机中加入少许纯净水&#xff0c;打成菠萝汁备用 4.打好…

伊犁-linux root 密码忘记咋办

1 root 密码忘记了 或者reboot 重启之后在引导界面 按住 e 进入如下界面 然后按住ctrlx 进入这个界面 root 修改成功

为什么512G的固态硬盘,电脑显示只有476G可用?

硬盘的标称容量与操作系统显示的可用容量存在差异&#xff0c;这是由于硬盘制造商和操作系统在计算容量时采用不同的进制标准所致。硬盘制造商通常使用10进制来标注硬盘容量&#xff0c;即1GB等于1000MB&#xff0c;而操作系统则使用2进制&#xff0c;即1GB等于1024MB。因此&am…

无人机视角电力巡检资产检测与异常判别数据集

无人机视角电力巡检资产检测与异常判别&#xff0c;资产检测关注17类目标&#xff0c;共10000余张无人机图像&#xff0c;json方式标注&#xff0c;类别如下&#xff1a; 1.Spiral Damper - 螺旋阻尼器 2.Stockbridge Damper - 斯托克布里奇阻尼器 3.Glass Insulator - 玻璃绝缘…

双击就可以打开vue项目,而不用npm run dev

右键点击桌面或其他位置&#xff0c;选择“新建” -> “快捷方式”&#xff0c;在“对象的位置”处直接输入“npm run dev”&#xff0c;然后下一步 自定义一个快捷方式名称 完成后&#xff0c;桌面会创建一个快捷方式&#xff0c;右键快捷方式选择属性&#xff0c;可以看…

智慧火灾应急救援航拍检测数据集(无人机视角)

智慧火灾应急救援。 无人机&#xff0c;直升机等航拍视角下火灾应急救援检测数据集&#xff0c;数据分别标注了火&#xff0c;人&#xff0c;车辆这三个要素内容&#xff0c;29810张高清航拍影像&#xff0c;共31GB&#xff0c;适合森林防火&#xff0c;应急救援等方向的学术研…

免费音乐剪辑软件大揭秘:2024 大学生的音乐创作利器

对于音乐爱好者而言&#xff0c;如果你萌生了尝试音乐剪辑的念头&#xff0c;不妨先从探索一些免费工具开始。在此&#xff0c;我愿分享几款我个人体验过的、值得一试的音乐剪辑免费软件&#xff0c;希望能为你的音乐探索之旅增添乐趣与灵感。 1.福晰音频剪辑 链接直达>&g…

Java servlet《网吧机房管理系统浅析》

网吧机房管理系统在网吧运营中起着至关重要的作用。 对于用户而言&#xff0c;该系统提供了便捷的登录方式&#xff0c;通过用户名和密码可准确显示所在网吧机房号&#xff0c;便于快速定位。同时&#xff0c;合理的机房分配功能确保用户获得良好上网体验。遇到问题时&#xff…

Highcharts甘特图基本用法(highcharts-gantt.js)

参考官方文档&#xff1a; https://www.highcharts.com/docs/gantt/getting-started-gantt https://www.highcharts.com/demo/gantt/project-management https://www.hcharts.cn/demo/gantt 链接在下面按需引入 https://code.highcharts.com/gantt/highcharts-gantt.js htt…