【leetcode学习笔记】岛问题

这篇博客介绍了如何解决0-1矩阵中的岛问题,即找出连通的1区域的数量。首先,通过深度优先搜索(DFS)算法进行遍历,将连通的1标记为2,并计数。然后,进一步探讨使用并查集实现并行解决方案,通过分割矩阵并处理边界点,确保正确合并不同部分的岛,最终得到总岛数。这种方法适用于大规模数据并行处理。

一、岛问题

 

问题:假设一个M\times N的0-1矩阵,每个位置都可以和自己的上下左右四个位置相连,如果有一片1连在一起,这一部分叫做一个岛,求一个矩阵中有多少个岛?

举例:

001010

111010

100100

000000

这个矩阵中有三个岛

二、DFS算法求解

可以考虑借助感染过程来设计算法。即,遍历所有节点,如果该节点的值是1,则使用深度遍历算法把这点相连的所有点值都变成2。统计执行了多少次感染过程即可。

class Solution{
    public int islandNum(int[][] matrix){
        int M = matrix.length;
        int N = matrix[0].length;
        int res = 0;
        for(int i = 0; i < M; i++){
            for(int j = 0; j < N; j++){
                if(matrix[i][j] == 1){
                    infect(matrix, i, j, M, N);
                    res++;
                }
            }
        }
        return res;
    }
    
    public void infect(int[][] matrix, int i, int j, int M, int N){
        if(i < 0 || j < 0 || i >= M || j >= N || matrix[i][j] != 1){
            return;
        }
        matrix[i][j] = 2;
        infect(matrix, i-1, j, M, N);
        infect(matrix, i+1, j, M, N);
        infect(matrix, i, j-1, M, N);
        infect(matrix, i, j+1, M, N);
    }
}

三、并查集求解

进阶的方式是设计一个可以并行的解,显然上述的算法不能满足要求,必须要借助并查集来实现。

3.1 并查集

假设我们有N个元素,一开始这N个元素分别归属于N个集合。我们需要设计一个数据结构,能够以较低的时间复杂度实现以下两个功能:

1.判断两个元素是否满足一个集合(查)

2.把两个元素所在的集合合成一个集合(并)

具体操作为:

初始化的时候,每个元素设置一个父元素,都设置为自己。这样,每个集合都存在一个代表元素。这个元素的父元素是自己,该集合中其他元素经过有限次“取父元素”的操作后,都会停留在代表元素上。该代表元素即为集合中所有元素的head节点。

判断a和b是否为一个集合时,找到a和b的head节点,判断两者是否相等。

合并a和b所在的集合时,先找出a和b距离各自head节点的距离,把链短的head节点的父节点变为链长的head节点。

注:在findHead的过程中,可以把链扁平化。比如说,a的父是b,b的父是c,c的父是d,d的父是d。那么在找到head节点d之后,返回结果之前,先把a、b、c、d的父节点都统一变为d,这样在后续的并查过程,就可以节省时间。

3.2 并行求解岛问题

并行的关键在于,把一个大图分成几个小图,让各个机器并行处理各个小图。然后再把小图的结果汇总。主要问题在于,一个岛可能在分割过程中被分成两部分,因此每个小图的岛的数量的和可能大于大图的岛的数量。为了能够实现岛的合并过程,我们就可以借助并查集来实现这个过程。

第一步:对于每个独立的小图,并行运算,分别使用感染过程,得到每个小图的岛的数量。同时,使用并查集结构,将每个被感染的点的父节点设置成感染它的源头。

第二步:遍历所有出现在边界两侧的点对,如果两个点都被感染了,且两个点不在一个集合里(查),那么将这两个点所在的集合合并(并),然后总岛数减1。

这样我们就得到了总的岛数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值