并查集的应用-岛屿数量问题

本文探讨如何利用并查集解决LeetCode中的200题——岛屿数量。通过对给定的二维网格进行分析,将每个1视为一个节点,并根据相邻规则建立联系,使用并查集算法来计算连通的岛屿数量。文章提供了修正后的并查集实现,并分析了代码优化的可能性。
摘要由CSDN通过智能技术生成

并查集的应用

上篇文章我们了解了并查集的内容,点这里看原文。而本文主要以leedcode题库中的两道题,来说下并查集的应用。

第一题:200.岛屿数量

给你一个由 ‘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
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

题目分析

此题目还有别的解法,这里我们只讨论并查集的解法。

这个问题跟 547.朋友圈(如没有看过朋友圈问题,可以查看并查集总结,有朋友圈问题的介绍)是有一些区别的。朋友圈问题的二维矩阵是主队对角线全为1的对称矩阵,横纵编号代表学生编号,且横纵编号对应相同的编号是同一个人,就是以一个个体人为节点使用UnionFind算法。

但这个岛屿问题的二维矩阵,横纵坐标更像是经纬度,横纵编号没有特定的相同之处,那么这个题目是否可以使用并查集求解呢?

答案是肯定的。

如果在这里我们以二维矩阵中的每一个元素作为一个节点,那么等价关系就可以是:如果这个节点值是“1”,与这个节点的上下左右相邻的节点值也是“1”这样的【等价关系】。这样考虑的等价关系,就可以使用并查集了。

如果还想不通,还记得上篇文章举的例子吗?

如果人步行就可以从一个岛屿走到另一个岛屿,我们就可以说这两个岛屿是连通的。那么这里我们把每个值是“1”的节点,想象成是独立的岛屿,而如果两个岛屿之间是上下左右相邻的话,就相当于在这两者之间建立了桥,这样就可以连通起来,视为一个岛屿。

是不是一下子就想到可以用并查集求解了呢?

这样一来,相较上篇文章,UnionFind类里一些方法就需要修正一下:

首先是初始化时的构造函数,

由于我们计划使用二维矩阵中每个元素作为节点,那么传入的参数可以直接使用二维矩阵grid[][]。

这里有个关键之处就是count,连通分量的计数器,在这里初始化的值应该是开始时“互相独立”的岛屿,即节点数为“1”的节点总数,是通过先设count=0;再遍历整个二维数组,如果节点值为“1”,就count加1,就正好是节点值为“1”的节点总数了。

还有一个点,就是parent数组,采用一维数组就可以记录某节点的父亲节点,采用二维位置与一维下标一一对应即可,这里使用 i * grid[0].length + j 做映射。
代码如下:

class UnionFind_2{
       
	private int count;    
	private int[] parent;    
	private int[] size;    
	public UnionFind_2(char[][] grid){
           
		int m = grid.length;        
		int n = grid[0].length;        
		this.count = 0;        
		parent = new int[m * n];       
		size = 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++;               
		 	    }                
		 	    size[i * n + j] = 1;            
		       } 
		 }
	}
    	//...
}

UnionFind类中其他方法没有改变,如下

private int find(int p){
       
	int x = p;   
	while (parent[x] != x){
           
		parent[x] = parent[parent[x]];        
		x = parent[x];    
	}    
	return x;
}
public void 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值