LeetCode200.岛屿数量

看完题目我还感觉这道题目有点难,没想到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.hqwc.cn/news/169465.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

经典OJ题:重排链表

题目&#xff1a; 给定一个链表&#xff0c;在进行重排前&#xff1a; 进行重排链表后&#xff1a; 如上图所示&#xff0c;所谓的重拍链表&#xff0c;就是将第一个节点连接第倒数第一个节点&#xff0c;第二个节点连接倒数第二个节点&#xff0c;以此类推&#xff0c;最后在连…

灰度与二值化

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…

环境变量小节

这是写的第二篇环境变量博客&#xff0c;写了一年多了&#xff0c;第一次出现把自己博客删了的情况&#xff0c;不知道为什么明明发表了&#xff0c;然后就把草稿箱和回收站的删了&#xff0c;结果晚上发现没发表&#xff0c;回收站删除是无法找回的&#xff0c;以后还是要慎重…

无线充,大功率小家电,智能家居,无人机快速充电等产品供电 LDR6328S芯片TYUPE-C PD诱骗电压 USB-C解决PD电源取电问题

LDR6328S 是乐得瑞科技有限公司开发的一款兼容 USB PD、QC 和 AFC 协议的 Sink 控制器。 LDR6328S 从支持 USB PD、QC 和 AFC 协议的适配器取电&#xff0c;然后供电给设备。比如可以配置适配器输 出需要的功率&#xff0c;给无线充电器设备供电。LDR6328S 也兼容传统 USB 电源…

QT 布局管理综合实例

通过一个实例基本布局管理&#xff0c;演示QHBoxLayout类、QVBoxLayout类及QGridLayout类效果 本实例共用到四个布局管理器&#xff0c;分别是 LeftLayout、RightLayout、BottomLayout和MainLayout。 在源文件“dialog.cpp”具体代码如下&#xff1a; 运行效果&#xff1a; Se…

Unity--视觉组件(Raw Image,Mask)||Unity--视觉组件(Text,Image)

1.Raw Image 2.mask “”Raw Image&#xff1a;“” Texture&#xff1a;&#xff08;纹理&#xff09; 表示要显示的图像的纹理&#xff1b; Color&#xff1a;&#xff08;颜色&#xff09; 应用于图像的颜色&#xff1b; Material&#xff1a;&#xff08;材质&#xff09…

AlGaN/GaN HFET 五参数模型

标题&#xff1a;A Five-Parameter Model of the AlGaN/GaN HFET 来源&#xff1a;IEEE TRANSACTIONS ON ELECTRON DEVICES&#xff08;15年&#xff09; 摘要—我们引入了AlGaN/GaN异质结场效应晶体管&#xff08;HFET&#xff09;漏极电流Id&#xff08;Vgs&#xff0c;Vds…

第四节(2):修改WORD中表格数据的方案

《VBA信息获取与处理》教程(10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互联网…

自适应AI chatGPT智能聊天创作官网html源码/最新AI创作系统/ChatGPT商业版网站源码

源码简介&#xff1a; 自适应AI chatGPT智能聊天创作官网html源码&#xff0c;这是最新AI创作系统&#xff0c;作为ChatGPT商业版网站源码&#xff0c;它是支持创作、编写、翻译、写代码等。是一个智能聊天系统项目源码。 注意&#xff1a;这个只是网站html源码&#xff0c;要…

MongoDB基础知识~

引入MongoDB&#xff1a; 在面对高并发&#xff0c;高效率存储和访问&#xff0c;高扩展性和高可用性等的需求下&#xff0c;我们之前所学习过的关系型数据库(MySql,sql server…)显得有点力不从心&#xff0c;而这些需求在我们的生活中也是随处可见的&#xff0c;例如在社交中…

基于Matlab+ AlexNet神经网络的动物识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于Matlab和AlexNet神经网络的动物识别系统可以用于自然图像识别等场景&#xff0c;以下是一个基本的介绍设计步骤…

Linux每日智囊

每日分享三个Linux命令&#xff0c;悄悄培养读者的Linux技能。 whatis 作用 查询指定命令的功能&#xff0c;将结果显示在终端上 语法 whatis 命令 案例 查询指定命令的功能 whatis sleeptouch 作用 修改已有文件的时间戳 (不常用)创建新的空文件 (常用) 语法 touc…