当前位置: 首页 > news >正文

LeetCode Java 队列结合广度优先算法(BFS)实现岛屿个数计算,附带详细分析


理解:不吐槽了。。。

  

分析:借由广度优先算法的思想,先循环根节点的海域,接着是根节点外面的第一层海域,然后是与第一层相邻的第二层海域,以此类推,探索过的位置不需要探索,直到探索完全部海域。
如果用树的形式来解释,就是按照:A➡B➡C➡D➡E➡F➡G 的顺序去探索

实现:接下来就是具体的实现,对于代码层面上的分析,我都详细的写在注释上了

/**
 * BFS 广度优先算法实现岛屿个数探索
 * @author: author
 * @create: 2019-07-31 13:44
 **/
public class IsLandBfs {

    /**
     * 判断是否是岛屿,然后统计岛屿数量
     * @param isLand 未知海域数组
     * @return 返回岛屿数量
     */
    public static Integer isLand(int[][] isLand) {

        // 都没东西玩啥
        if (isLand.length == 0) {
            return 0;
        }

        // 岛屿数量
        int count = 0;

        // 循环未知海域的二维数组
        for (int i = 0; i < isLand.length; i ++) {
            for (int j = 0; j < isLand[i].length; j ++) {

                // isLand 拥有的值有:1 未探索的岛屿,0 海域,-1 已探索的岛屿
                // isLand 为 1 表示这个是未探索岛屿(根节点),你也可以看作最初的登陆点
                // 至于已探索岛屿肯定是与之前岛屿相连,无需重复探索
                if (isLand[i][j] == 1) {
                    count ++;
                    System.out.println("岛屿登陆点(根节点),这是发现的第" + count + "座岛屿");
                }
                // 开始 BFS 广度优先算法探索岛屿
                visitLand(isLand, i, j);
            }
        }
        return count;
    }

    /**
     * BFS 广度优先算法岛屿探索,从岛屿的根节点开始
     * 把与这个岛屿相连的岛屿全部在 isLand 中状态变为 -1,防止重复探索
     * @param isLand
     * @param i
     * @param j
     */
    public static void visitLand(int[][] isLand, int i, int j) {

        // 声明队列
        Queue<Integer> queue = new LinkedList<>();

        // 在后面 while 的循环中,如果是岛屿,也会陆续把这个岛屿周围的点的定位添加到队列中
        // 所有点都以 先 i,后 j,的顺序添加,因此队列以 i,j 交错的形式存在
        // i 与后一个 j 组成一个需要探索的位置,也可以理解成一个需要探索点的坐标
        // 而探索的顺序就是从根节点开始,第一层的点全部探索完后,之后探索第二层的所有点,以此类推
        // 不太理解的需要好好理解下
        // 把 i 放入队列
        queue.offer(i);

        // 把 j  放入队列
        queue.offer(j);

        // 循环队列
        // 每次循环都取一对 i,j,以此锁定一个需要探索的海域
        while (!queue.isEmpty()) {

            // 队列的 poll 方法会把队列最前面的值返回后,把这个值删除
            i = queue.poll();

            j = queue.poll();

            // 如果这个点是海域或者已探索的岛屿都跳过
            if (isLand[i][j] != 1) {
                continue;
            }

            // 记录下这个点探索过了,把探索过的点状态变为 -1
            isLand[i][j] = -1;

            // 把这个点的上面点加入队列
            // 这里注意:i 是循环行, j 是循环列
            // 比如: i = 2,i - 1 就是从第 2 行向第 1 行去探索,是向上
            // 不理解的可以好好捋一捋
            if (i - 1 >= 0) {
                queue.offer(i - 1);
                queue.offer(j);
            }

            // 把这个点的下面点加入队列
            if (i + 1 < isLand.length) {
                queue.offer(i + 1);
                queue.offer(j);
            }

            // 把这个点的左面点加入队列
            if (j - 1 >= 0) {
                queue.offer(i);
                queue.offer(j - 1);
            }

            // 把这个点的右面点加入队列
            if (j + 1 < isLand[i].length) {
                queue.offer(i);
                queue.offer(j + 1);
            }
        }
    }

    public static void main(String[] args) {
        
        // 岛屿 二维数组(图形化)
        int [][] isLand = {{1, 1, 0, 0, 0},{1, 1, 0, 0, 0},{0, 0, 1, 0, 0},{0, 0, 0, 1, 1}};
        int count = isLand(isLand);
        System.out.println("一共探索到" + count + "座岛屿");
    }
}

附带下队列方法解释:

add        增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
offer       添加一个元素并返回true       如果队列已满,则返回false
poll         移除并返问队列头部的元素    如果队列为空,则返回null
peek       返回队列头部的元素             如果队列为空,则返回null
put         添加一个元素                      如果队列满,则阻塞
take        移除并返回队列头部的元素     如果队列为空,则阻塞

说实话,比起广度优先,我觉得深度优先的代码层面上更好理解一些

Java 深度优先算法(DFS)实现岛屿个数计算,附带详细分析

相关文章:

  • navicat连接oracle报错:ORA-12737 Instant Client Light:unsupported server character set ZHS16GBK
  • Spring Boot,Spring Cloud,Spring Cloud Alibaba 版本选择说明以及整理归纳
  • RestTemplate 工具类
  • SpringCloud 之 Ribbon
  • SpringCloud 之 Hystrix 断路器,服务降级,自定义配置
  • Oracle 让指定数据排在最前面
  • Gitlab 之 Windows 环境进行 tomcat 持续集成部署,包含项目打包,备份,部署以及问题
  • Git 克隆指定分支的代码
  • Vue 新手学习笔记:vue-element-admin 之 入门开发教程(v4.0.0 之后)
  • Tomcat 内存优化
  • SpringCloud 之 Zuul 基础使用与进阶
  • Navicat 连接 sqlserver 带端口号配置
  • SpringCloud 之 Config 配置中心与动态刷新
  • Java 基础:队列
  • Java 基础:栈
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • Brief introduction of how to 'Call, Apply and Bind'
  • canvas绘制圆角头像
  • chrome扩展demo1-小时钟
  • EventListener原理
  • leetcode-27. Remove Element
  • Lucene解析 - 基本概念
  • Sass 快速入门教程
  • vue的全局变量和全局拦截请求器
  • 分享几个不错的工具
  • 官方解决所有 npm 全局安装权限问题
  • 前言-如何学习区块链
  • HanLP分词命名实体提取详解
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #QT项目实战(天气预报)
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • (06)Hive——正则表达式
  • (12)Linux 常见的三种进程状态
  • (MATLAB)第五章-矩阵运算
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (蓝桥杯每日一题)love
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • .NET 8.0 中有哪些新的变化?
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .net 后台导出excel ,word
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • @Autowired多个相同类型bean装配问题
  • [c++] C++多态(虚函数和虚继承)
  • [C++]C++类基本语法
  • [C语言]编译和链接
  • [Django 0-1] Core.Checks 模块
  • [Godot] 3D拾取
  • [hive] posexplode函数