Leetcode【DFS BFS】

2023-11-17

Leetcode | 200. 岛屿数量

题目

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
 输入:
 11110
 11010
 11000
 00000
 输出: 1
示例 2:
 输入:
 11000
 11000
 00100
 00011
 输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands

解题

思路

 因为岛屿是连通着的1,很容易想到DFS和BFS,从一个1点出发,可以把它连通着的所有1(连通的邻接点有四个方向:上下左右)搜索出来,这就是一个岛屿。而我们进行几次dfs/bfs搜索就是一共有几个岛屿。详细DFS和BFS的搜索方法介绍见图/树的遍历:深度优先遍历DFS和广度优先遍历BFS详解与java实现
 具体代码怎么设计实现,就有以下几个问题:① 从哪个1出发,怎么选择每个岛屿的第一个1?② 怎么确保下一个搜索选择的1是没有被搜索过的岛屿?
 上述问题的解决方法:本来想着是将二维数组中所有的1用另一种数据结构存储起来,依次遍历作为搜索开始点,搜索过的1就从存储结构里删除;等这次搜索结束后,从存储结构里的下一个1开始下一次搜索。但是实现起来比较麻烦,也需要额外的内存空间。
 另一种更好的解决方法就是在grid数组里原地搜索,不占用额外的内存空间。

  1. 依次遍历整个网格,当遇到1时,就开始dfs/bfs
  2. 然后每次搜索到哪个点就把哪个点的值赋值为0,这样确保了下一次dfs/bfs不会再选择这个点,解决了问题②。
  3. 在遍历整个网格的过程中,进行一个dfs/bfs,岛屿数量res+1, 表示多一个岛屿。

DFS解法

 递归求解

需要注意的是,dfs的递归求解中,遍历到每一个点时,在递归它的邻接点之前,一定要确保它的那个邻接点存在,因为不存在就不用判断/搜索这个点。而这种判断情况很复杂,因为邻接点存在的条件很多样。所以我们写代码时可以采用排除法,反向思考,不判断点是否存在,而是判断点是否不存在,将不存在的情况排除。
具体操作:递归每个点时,不判断每个邻接点是否存在再递归这个邻接点,而是假设都存在先递归邻接点,然后在每次递归的方法里先判断这个点存不存在,将不存在的情况(比如在方格外或不满足条件)列出来,直接返回不用继续递归。

 在该题中,邻接点存在的条件是:

  1. 在该点的水平/竖直方向上的相邻,即上下左右四个点;
  2. 值为1;
  3. 在网格内。

 时间复杂度:O(mn),m和n分别为行数和列数
 空间复杂度:O(mn),因为dfs的深度最坏为整个陆地为mn

class Solution {
    public int numIslands(char[][] grid) {
        //深度优先搜索 递归
        int res = 0;
        int m = grid.length;//行数
        //特殊情况
        if(grid == null ||m == 0) return 0;
        //因为当rown等于0时,coln根本算不出来,所以要先判断
        int n = grid[0].length; //列数

        for(int i = 0;i < m;i++){
            for(int j = 0; j < n; j++){
                if(grid[i][j] == '1'){
                    res++;
                    //从(i,j)位置开始搜索,将搜索到的1值都标记为0,说明已经访问过,属于这次搜索的岛屿中的,下一次深度搜索已经不需要了。
                    dfs(i,j,grid);
                }
            }
        }
        return res;
    }
    public void dfs(int i, int j,char[][] grid){
        int m = grid.length;//行数
        int n = grid[0].length; //列数
        //如果当前值已在边界外 或者当前值为0就直接返回,因为只需要搜索边界内的1值
        if(i >= m || j>=n || i < 0 || j < 0 || grid[i][j] == '0') return;
        //当当前访问到的(i,j)值标记为0,表示已访问过
        grid[i][j] = '0';
        //递归搜索它的四个邻接点
        dfs(i+1,j,grid);//下邻接点
        dfs(i-1,j,grid);//上邻接点
        dfs(i,j+1,grid);//右邻接点
        dfs(i,j-1,grid);//左邻接点
    }
}

DFS结果

BFS解法

 主循环和dfs解法一样,不同的就在于搜索连通的1的方式不同。BFS主要通过队列来实现,将初始1压入队列,然后弹出一个1将其符合条件的邻接点压入队列中,再弹出1,再压入它的邻接点们~;直至队列为空表示此次BFS结束。
 时间复杂度:O(mn),m和n分别为行数和列数
 空间复杂度:O(min(m,n)),因为bfs最坏的情况下队列的长度可达到min(m,n)

class Solution {
    public int numIslands(char[][] grid) {
        //bfs  队列
        int res = 0;
        int m = grid.length;//行数
        //特殊情况
        if(grid == null ||m == 0) return 0;
        //因为当rown等于0时,coln根本算不出来,所以要先判断
        int n = grid[0].length; //列数

        //初始化一个队列
        Queue<int[]> queue = new LinkedList<>();
        for(int i = 0;i < m;i++){
            for(int j = 0; j < n; j++){
                if(grid[i][j] == '1'){
                    res++;
                    //从(i,j)位置开始搜索,将搜索到的1值都标记为0,说明已经访问过,属于这次搜索的岛屿中的,下一次深度搜索已经不需要了。
                    grid[i][j] = '0';
                    //bfs:将该点的所有值为1的邻接点加入队列中,队列每弹出一个点,继续加入该点的所有邻接点直到队列空为止
                    queue.offer(new int[]{i,j});//将初始1压入队列
                    while(!queue.isEmpty()){
                        int[] temp = queue.poll();//弹出一个元素temp
                        //将temp的邻接点压入队列中
                        //temp的上邻接点存在的话
                        if(temp[0]-1 >=0 && grid[temp[0]-1][temp[1]] == '1'){
                            queue.offer(new int[]{temp[0]-1,temp[1]});
                            grid[temp[0]-1][temp[1]] = '0';
                        }
                        //temp的下邻接点存在的话
                        if(temp[0]+1 <m && grid[temp[0]+1][temp[1]] == '1'){
                            queue.offer(new int[]{temp[0]+1,temp[1]});
                            grid[temp[0]+1][temp[1]] = '0';
                        }
                        //temp的左邻接点存在的话
                        if(temp[1]-1 >=0 && grid[temp[0]][temp[1]-1] == '1'){
                            queue.offer(new int[]{temp[0],temp[1]-1});
                            grid[temp[0]][temp[1]-1] = '0';
                        }
                        //temp的右邻接点存在的话
                        if(temp[1]+1 <n && grid[temp[0]][temp[1]+1] == '1'){
                            queue.offer(new int[]{temp[0],temp[1]+1});
                            grid[temp[0]][temp[1]+1] = '0';
                        }
                    }
                }
            }
        }
        return res;
    }
}

bfs结果

参考:leetcode官方题解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Leetcode【DFS BFS】 的相关文章

  • Mybatis简单的增删改查和mybatis配置文件的详解

    MyBatis 1 什么是Mybatis MyBatis是一款优秀的持久层框架 MyBatis避免了几乎所有的JADBC代码和手动设置参数以及获取结果集 MyBatis可以使用简单的XML或注解来配置和映射原生类型 接口和Java的POJO
  • 使用Jest测试接口时间

    引言 在开发和测试过程中 我们经常需要对接口的性能进行评估和优化 一个重要的指标是接口的执行时间 本文将介绍如何使用Jest来测试接口的执行时间 并提供示例代码 Jest简介 Jest 是一个流行的JavaScript测试框架 广泛应用于前

随机推荐

  • 整理了60个 Python 实战例子,拿来即用

    大家好 最近有一些朋友问我有没有一些 Python 实战小案例 今天我整理排版了一遍 给大家分享一下 喜欢记得点赞 收藏 关注 整理了60个Python小例子 拿来即用 一 数字 1 求绝对值 绝对值或复数的模 公众号 快学Python I
  • python与pyqt5把列表中的数据写入到一个新的excel表中,并选择保存路径

    您可以使用 Python 的 openpyxl 库来实现这个功能 首先 您需要通过在命令行中运行 pip install openpyxl 来安装 openpyxl 库 然后 您可以使用以下代码来将列表中的数据写入新的 Excel 表中 f
  • mysql中drop语法错误,mysql 中drop 库的问题

    最近drop database pai 报错 ERROR 1010 HY000 Error dropping database can t rmdir pai errno 39 我就想把库文件直接删除试试 于是 rm rf usr loca
  • 区块链的基本概念

    区块链是分布式数据存储 点对点传输 共识机制 加密算法等计算机技术的新型应用模式 所谓共识机制是区块链系统中实现不同节点之间建立信任 获取权益的数学算法 区块链技术的内涵可概括为 在缺少可信任的中央节点和可信任的通道的情况下 分布在网络中的
  • All O`one Data Structure

    学习地址 双向链表 key为count数 value为存入的字符串 增加一个字符串 先判断其Node位置 再在双向链表中插入 删除也是 最大最小的字符串数在双向链表的表尾和表头 记录学习一下 class AllOne Node root M
  • STM32的介绍及MDK

    文章目录 STM32介绍 单片机 STM32命名 armV7的三个系列 STM32系统结构 CMSIS标准 STM32F4方包绍官方库包 STM32F103 STM32F103资源 STM32F103总线架构 STM32F103引脚 STM
  • 基于keras的图像分类CNN模型的搭建以及可视化(附详细代码)

    基于keras的图像分类CNN模型的搭建以及可视化 本文借助keras实现了热图像的分类模型的搭建 以及可视化的工作 本文主要由以下内容组成 Keras模型介绍 CNN模型搭建 模型可视化 Keras模型介绍 简介 Keras 是 Goog
  • Canvas实例之鼠标移动特效(彩色小球)

    实现鼠标移动跟随着绽放的彩色小球 完整代码在文档末尾 图示 思路 获取画布 获取画布 var canvas document getElementById mycanvas 获取上下文 var ctx canvas getContext 2
  • 嵌入式毕业设计 树莓派实现口罩佩戴检测识别 - 单片机 物联网 机器视觉

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 硬件设计 树莓派4B 5 软件说明 Debian Pi Aarch64 树莓派操作系统 vnc 远程连接树莓派 opencv 摄像头人脸数据采集 人脸数据显示等 6 部分核心代码
  • 顺序表、链表元素的就地逆置。

    目录 一 顺序表元素的就地逆置 1 完整代码 2 解题思路流程 二 链表元素的就地逆置 1 完整代码 2 解题思路流程 一 顺序表元素的就地逆置 1 完整代码 include
  • Vue的生命周期

    一 初始化阶段 1 new Vue Vue实例化 组件也是一个小的Vue实例 2 Init Events Lifecycle 初始化事件和生命周期函数 3 beforeCreate 生命周期钩子函数被执行 4 Init injections
  • 战争科学论——认识和理解战争的科学基础和思维方法

    胡晓峰 1973年中学毕业赴湖南农村插队当过三年知青 1976年回城后当过工人 1977年考入国防科技大学系统工程与数学系信息系统工程专业学习 1981年底毕业后留校任教 后又攻读了研究生 1987年在读信息系统工程研究生期间 曾赴美国加州
  • GDAL-2.4.0 获取Hadoop-3.1.2 hdfs tif文件信息

    GDAL 2 4 0 获取Hadoop 3 1 2 hdfs tif文件信息 GDAL 2 4 0增加了以下功能 Add vsihdfs virtual file system handler for Hadoop File System
  • Android 反编译Apk,修改资源,重新打包,签名发布

    本文简单介绍apk是如何修改logo ic launcher 类似的资源文件修改也可以通过此方式 不过要修改class的话就要涉及到smali的学习了 这里就暂且不谈 后续有需要再做更新 一 工具介绍 apktool 用来反编译apk ap
  • 【华为OD机试真题 JAVA】最多的连续胡杨棵树

    标题 最多的连续胡杨棵树 时间限制 1秒 内存限制 262144K 语言限制 不限 近些年来 我国防沙治沙取得显著成果 某沙漠新种植N棵胡杨 编号1 N 排成一排 一个月后 有M棵胡杨未能成活 现可补种胡杨K棵 请问如何补种 只能补种 不能
  • 【JS基础】通俗易懂的讲清楚去抖/防抖、节流。外加手写深度比较

    文章目录 去抖 防抖 思路解析 节流 两者在vue中结合计算属性使用 深度比较 去抖 防抖 去抖也叫防抖 为了照顾JS初学者的理解和记忆 我就简单的说明一下 我们生活中很多出现抖动的现象 都是没有规律的 例如人的发抖 树叶在风中的抖动 海浪
  • java mysql 断开连接_mysql java连接异常及断开解决秘籍

    3 The last packet sent successfully to the server was 0 milliseconds ago The driver has not received any packets from th
  • 前端一年的经验,面试官都会问一些什么问题呢?都是这样一些的问题

    面试准备阶段 学习以及复习基础知识 这一定是第一步需要做的事情 先制定规划 然后按照这一条既定的规划去学习以及复习 可分为六部分去准备 css部分 像 css这一部分 面试必问 但是它的东西很杂很多 我不知道有多少人和我感觉一样 学习前端最
  • Oracle中Delete和Commit操作的流程分析

    以后还会陆续加入其他各种操作的实现机制 1 删除 Delete 流程 Oracle读Block 数据块 到Buffer Cache 缓冲区 如果该Block在Buffer中不存在 在Redo Log Buffer 重做日志缓冲区 中记录De
  • Leetcode【DFS BFS】

    Leetcode 200 岛屿数量 题目 解题 思路 DFS解法 BFS解法 题目 给你一个由 1 陆地 和 0 水 组成的的二维网格 请你计算网格中岛屿的数量 岛屿总是被水包围 并且每座岛屿只能由水平方向和 或竖直方向上相邻的陆地连接形成