LeetCode200.岛屿数量

news2024/11/19 1:44:17

看完题目我还感觉这道题目有点难,没想到20分钟不到就完全靠自己给写出来了。我就是按照自己的想法来,我用一个等大的visit数组来表示grid数组中的这个元素是否被访问过(是否已经被判断了是不是岛屿)。

先用一个大的循环对grid数组遍历,去判断里面的元素grid[i][j]是不是一个岛屿。如果它是一个岛屿的话,就要把岛屿数量+1,并且要把和grid[i][j]相连的陆地全部算在这个岛屿中,所以要把和它相连的陆地的visit设置成true,下次遍历到这个点就直接跳过。

那么如何把grid[i][j]的相连的陆地的visit全部置为true呢,利用递归就可以了,用setVisit(char[][] grid, boolean[][] visit, int i, int j),grid数组和visit数组就是全局的grid数组和visit数组(如果把这两个数组定义在类里面就不用传这两个参了),i,j就是要进行置true的元素下标,先把visit[i][j]置为true,然后再递归调用setVist()方法把visit[i][j]的上下左右4个方向的visit置为true,当然不是直接置true,要进行判断,假设相邻位置是m,n,首先必须要m,n大于等于0小于length,其次grid[m][n]要等于1并且visit[m][n]要等于false,然后直接递归调用setVisit方法把visit[m][n]置为true,这样进行递归就会把与grid[i][j]相连的所有陆地都visit了,

那么如何判断grid[i][j]是不是岛屿呢?其实很简单,如果grid[i][j]是1并且它没有被visit过他就是岛屿,因为它如果没有被visit过只有两种可能,第一种是没有任何陆地和它相连所以它没有被visit,第二种是它是它所在的岛屿第一个被发现的陆地,以上两种情况都可以把它判定为岛屿给岛屿属灵加一,最后返回岛屿数量result即可,以下是我的代码:

class Solution {
    public int numIslands(char[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        boolean[][] visit = new boolean [m][n];
        int result=0;
        
        for(int i =0;i<m;i++){
            for(int j=0;j<n;j++){
                if(grid[i][j] == '1' && !visit[i][j]){
                       result++;
                       setVisit(grid, visit, i, j);
                }
            }
        }
         return result;
    }

    public void setVisit(char[][] grid, boolean[][] visit, int i, int j){
        visit[i][j] =true;
        if(i+1<visit.length && grid[i+1][j] == '1' && visit[i+1][j] == false)setVisit(grid, visit, i+1, j);
        if(j+1<visit[0].length && grid[i][j+1] == '1' && visit[i][j+1] == false)setVisit(grid, visit, i, j+1);
        if(i-1>=0 && grid[i-1][j] == '1' && visit[i-1][j] == false)setVisit(grid, visit, i-1, j);
        if(j-1>=0 && grid[i][j-1] == '1' && visit[i][j-1] == false)setVisit(grid, visit, i, j-1);

    }
}

看看官方题解的做法吧:

题解的方法一用的是深度优先搜索,和我的方法是一样的,只不过它没有用标记数组visit,而是直接再grid数组上把相连的陆地由1改成了0,以下是题解方法一的代码:

class Solution {
    void dfs(char[][] grid, int r, int c) {
        int nr = grid.length;
        int nc = grid[0].length;

        if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') {
            return;
        }

        grid[r][c] = '0';
        dfs(grid, r - 1, c);
        dfs(grid, r + 1, c);
        dfs(grid, r, c - 1);
        dfs(grid, r, c + 1);
    }

    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }

        int nr = grid.length;
        int nc = grid[0].length;
        int num_islands = 0;
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    ++num_islands;
                    dfs(grid, r, c);
                }
            }
        }

        return num_islands;
    }
}

题解的方法二用的是广度优先搜索,如果gird[i][j]等于1就把它放到一个队列里面,然后不断的从队列中取出元素把grid置为0,每取出一个就把这个元素的上下左右放进队列(当然需要这些元素的grid为1),值得注意的是它放进队列的是这个元素在数组中的序号,也就是行号*每行的个数+列号,所以这个队列中的这个序号被取出来后会通过模运算算出行号和列号,方便找上下左右4个元素。以下是题解方法二的代码:

class Solution {
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }

        int nr = grid.length;
        int nc = grid[0].length;
        int num_islands = 0;

        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    ++num_islands;
                    grid[r][c] = '0';
                    Queue<Integer> neighbors = new LinkedList<>();
                    neighbors.add(r * nc + c);
                    while (!neighbors.isEmpty()) {
                        int id = neighbors.remove();
                        int row = id / nc;
                        int col = id % nc;
                        if (row - 1 >= 0 && grid[row-1][col] == '1') {
                            neighbors.add((row-1) * nc + col);
                            grid[row-1][col] = '0';
                        }
                        if (row + 1 < nr && grid[row+1][col] == '1') {
                            neighbors.add((row+1) * nc + col);
                            grid[row+1][col] = '0';
                        }
                        if (col - 1 >= 0 && grid[row][col-1] == '1') {
                            neighbors.add(row * nc + col-1);
                            grid[row][col-1] = '0';
                        }
                        if (col + 1 < nc && grid[row][col+1] == '1') {
                            neighbors.add(row * nc + col+1);
                            grid[row][col+1] = '0';
                        }
                    }
                }
            }
        }

        return num_islands;
    }
}

题解的方法三采用的是并查集的方法,这个方法有点复杂,先上代码:

class Solution {
    class UnionFind {
        int count;
        int[] parent;
        int[] rank;

        public UnionFind(char[][] grid) {
            count = 0;
            int m = grid.length;
            int n = grid[0].length;
            parent = new int[m * n];
            rank = new int[m * n];
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (grid[i][j] == '1') {
                        parent[i * n + j] = i * n + j;
                        ++count;
                    }
                    rank[i * n + j] = 0;
                }
            }
        }

        public int find(int i) {
            if (parent[i] != i) parent[i] = find(parent[i]);
            return parent[i];
        }

        public void union(int x, int y) {
            int rootx = find(x);
            int rooty = find(y);
            if (rootx != rooty) {
                if (rank[rootx] > rank[rooty]) {
                    parent[rooty] = rootx;
                } else if (rank[rootx] < rank[rooty]) {
                    parent[rootx] = rooty;
                } else {
                    parent[rooty] = rootx;
                    rank[rootx] += 1;
                }
                --count;
            }
        }

        public int getCount() {
            return count;
        }
    }

    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }

        int nr = grid.length;
        int nc = grid[0].length;
        int num_islands = 0;
        UnionFind uf = new UnionFind(grid);
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    grid[r][c] = '0';
                    if (r - 1 >= 0 && grid[r-1][c] == '1') {
                        uf.union(r * nc + c, (r-1) * nc + c);
                    }
                    if (r + 1 < nr && grid[r+1][c] == '1') {
                        uf.union(r * nc + c, (r+1) * nc + c);
                    }
                    if (c - 1 >= 0 && grid[r][c-1] == '1') {
                        uf.union(r * nc + c, r * nc + c - 1);
                    }
                    if (c + 1 < nc && grid[r][c+1] == '1') {
                        uf.union(r * nc + c, r * nc + c + 1);
                    }
                }
            }
        }

        return uf.getCount();
    }
}

它是采用了一个内部类UnionFind,这个类有一个count属性,表示岛屿的个数,parent[]数组,大小就是giad的数组的大小,grid的每个元素都在parent中有对应的位置,也是采用序号的方式(行号*每行的个数+列号),比如grid[i][j]在parent中对应的下标就是parent[i*每行个数+j],它表示grid[i][j]有那个序号的元素连接而找到,通过

public int find(int i) {
            if (parent[i] != i) parent[i] = find(parent[i]);
            return parent[i];
        }

就可以找到序号i元素的最大祖先,然后通过

public void union(int x, int y) {
            int rootx = find(x);
            int rooty = find(y);
            if (rootx != rooty) {
                if (rank[rootx] > rank[rooty]) {
                    parent[rooty] = rootx;
                } else if (rank[rootx] < rank[rooty]) {
                    parent[rootx] = rooty;
                } else {
                    parent[rooty] = rootx;
                    rank[rootx] += 1;
                }
                --count;
            }
        }

rank是一个和gird等大的数组,它表示rank[序号]所在树的深度,

假设grid[i][j]的序号是x,他的相邻元素的序号是y,通过find方法分别找到x和y的根节点rootx和rooty,如果rootx和rooty不相等说明他们之前在两颗独立的树上,因为x和y是相邻的,所以他们其实在同一颗树上,所以他们的树的深度是两颗树深度最大的一个,大的那个root是小的root的parent;如果两颗树的深度相等,那么可以把其中一个root挂在另一个root的叶子上,那么树的深度就+1了,因为他们两个树之前是独立的,但其实他们是一起的也就是说之前count多加了一次,所以count要-1,

只要在numIslands中把grid的每个节点遍历一次,最后返回count即可。

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

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

相关文章

threejs(12)-着色器打造烟雾水云效果

一、自己封装水波纹效果 src/main/main01.js import * as THREE from "three";import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import gsap from "gsap"; import * as dat from "dat.gui"; import ver…

解决springboot接受buffer文件为null(从picgo上传buffer看springmvc处理过程)

1. 前言&#xff1a; picgo插件的简单开发 上篇文章我们简单写了picgo上传插件&#xff0c;但是当我们测试的时候&#xff0c;发现问题了&#xff0c;后端MultipartFile file接受到的文件为null。 2. 排查问题&#xff1a; 参考的文档 picgo api列表关于multipart form-data中…

U-Mail邮件系统三大安全措施,防止信息泄露!

在当信息化高速发展的今天&#xff0c;国内很多企业业务流程对OA系统、CRM系统、ERP系统、邮件系统等办公应用依赖度越来越高。这些办公应用给企业带来便利的同时也伴随着越来越多的信息安全问题&#xff0c;而在日常的办公场景中&#xff0c;由于内部员工非法泄漏或黑客入侵导…

Qt实现TCP调试助手 - 简述如何在Qt中实现TCP多并发

简介 软件开发中&#xff0c;可能经常会用到TCP调试工具。本人使用QT开发了一款TCP调试工具&#xff0c;方便大家使用。本文章主要介绍下&#xff0c;该工具的功能&#xff0c;以及如何在Qt中实现TCP服务器的并发。 界面展示 安装界面 桌面图标。安装后会生成桌面图标&#…

(三)正点原子I.MX6ULL kernel6.1挂根文件系统

一、概述 移植NXP官方最新的linux kernel&#xff08;linux-imx-lf-6.1.y&#xff09; 移植方法基本参照正点原子教程 移植开发板&#xff1a;正点原子阿尔法2.1 二、添加开发板到内核 进入内核目录下&#xff0c;先修改Makefile 打开终端&#xff1a; cp arch/arm/configs/im…

fastbins_Double Free调试

我大哥给我出了一题pwn heap题&#xff0c;当时现场的时候没解出来&#xff0c;想岔了。事后感概自己还是理解的不够透彻。决定认真再次调试下。用的是2.23版本的how2heap中fastbins_dup.c。 简单用gcc编译下&#xff0c;然后带源码调试&#xff1a; 生成一个a.out的文件&#…

C++ 运算符重载(Complex复数类)

Complex复数类 Complex.h #ifndef COMPLEX_H #define COMPLEX_H#include <iostream> using namespace std;class Complex { private:double real 0; //复数的实部double imag 0; //复数的虚部 public:Complex() default; /*无参构造*/Complex(double r); …

No186.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

解决XFCE桌面VirtualBox透明背景的问题

1 背景 笔者用的是ManjaroXFCE的组合&#xff0c;但是在使用VirtualBox时&#xff0c;会出现透明背景的问题&#xff1a; 然后发现这其实和Kvantum主题有关。下面将进行设置操作&#xff0c;去修正Kvantum相关配置修复该问题。 2 操作流程 打开Kvantum Manager&#xff1a; …

No184.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

Django中如何创建表关系,请求生命周期流程图

Django中ORM创建表关系 如何创建表关系(一对一 &#xff0c; 一对多 &#xff0c; 多对多) 图书表&#xff0c;出版社表&#xff0c;作者表&#xff0c;作者详情表 换位思考法判断表关系 图书表和出版社表 >>> 一对多 >>> 图书表是多&#xff0c;出…

数据挖掘:关联规则,异常检测,挖掘的标准流程,评估指标,误差,聚类,决策树

数据挖掘&#xff1a;关联规则 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&#xff0c;尤其sql要…

混合A Star算法

混合A Star算法就是将A*与Lattice Graph相关联。 使用栅格地图&#xff0c;保持在栅格地图的这个节点方格里都只记录一个机器人的State&#xff0c;例如图上的弯弯的线&#xff0c;进行剪枝&#xff0c;看一个节点的Cost&#xff08;时间、消耗的能量、路径的长度、终端状态惩…

​软考-高级-系统架构设计师教程(清华第2版)【第3章 信息系统基础知识(p120~159)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第3章 信息系统基础知识(p120~159)-思维导图】 课本里章节里所有蓝色字体的思维导图

无需公网IP,贝锐花生壳内网穿透远程访问NAS

群晖DSM 7.0及以上版本 1.1 安装运行花生壳套件 &#xff08;1&#xff09;通过浏览器输入群晖NAS的内网地址&#xff0c;登录进去后&#xff0c;点击【套件中心】&#xff0c;搜索【花生壳】&#xff0c;并点击【安装套件】&#xff1b; &#xff08;2&#xff09; 勾选我接…

git命令汇总

1.git是基于ssh的代码管理工具,所以在git使用之前需要配置好ssh ssh配置教程 2.先创建仓库 3. git init在目标的git目录下创建仓库 4.git add .(或者写文件名) 5.git commit -m "标记信息" 持久化 6.git remote add origin gitgit.acwing.com:yaoaolong/11_5.git初次…

异步编程工具Promise与Async/Await:解决前端开发中的嵌套回调地狱

文章目录 Promise&#xff1a;处理异步操作的基本工具Promise.all async/await&#xff1a;更简洁的异步编程方式Promise与async/await的比较结论 当谈及JavaScript中的异步编程时&#xff0c;两个非常常见且强大的工具是Promise和async/await。在本文中&#xff0c;我们将以实…

CNN入门实战:猫狗分类

前言 CNN&#xff08;Convolutional Neural Network&#xff0c;卷积神经网络&#xff09;是一种深度学习模型&#xff0c;特别适用于处理图像数据。它通过多层卷积和池化层来提取图像的特征&#xff0c;并通过全连接层进行分类或回归等任务。CNN在图像识别、目标检测、图像分割…

ubuntu下tensorrt环境配置

文章目录 一、Ubuntu18.04环境配置1.1 安装工具链和opencv1.2 安装Nvidia相关库1.2.1 安装Nvidia显卡驱动1.2.2 安装 cuda11.31.2.3 安装 cudnn8.21.2.4 下载 tensorrt8.4.2.4 二、编写CMakeLists.txt三、TensorRT系列教程 一、Ubuntu18.04环境配置 教程同样适用与ubuntu22.04…

springcloud电影购票选座网站系统源码

开发技术&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea springcloud springboot mybatis vue elementui 功能介绍&#xff1a; 用户端&#xff1a; 登录注册 首页显示搜索电影&#xff0c;轮播图&#xff0c;电影分类&#xff0c;最近上架电影&#xff08;可…