并查集具体例题使用详解(力扣200岛屿数量)

 题目分析:

在二维空间中,只需要讨论每个1的上下左右是否为1即可。而利用并查集的方法,可以设每一个1是一个单独的集合,然后从第一行第一列依次往m行n列向四周寻找,当邻接元素为1时,则合并为同一个集合,遇到零则终止该行或列,最后再统计场上剩余的集合数量,便得到岛屿数量;

优化思路:

1,在寻找邻接的元素是否为1的时候,不需要上下左右四个方向的寻找,只需要向上或者向左查询是否为1,然后判断是否合并为同一个集合。因为当依次遍历查找元素的时候,查找的顺序是始终向右以及向下的,既这个元素无论如何都会被判断一次是否为1,便不需要再向右或下判断是否同为1,当遍历到这个数时,向上或向左判断就足够确认是否在同一个集合内了,即使不向右判断,下一次遍历也会跑到右边的元素身上,然后再向左向上判断是否为同为1(向下同理);

2,存储二维空间的坐标的时候,不一定需要用二维数组来存储,可以从第一个位置按照遍历的顺序,依次编号,使得在查询第 i 行第 j 列(默认从第0行第0列开始,共有 n 行 m 列)的元素时,使用公式来计算出他的一维对应位置坐标:id=i*m+j;

代码实现:

#include <vector>
using namespace std;

class Code05_NumberOfIslands {
public:
    int numIslands(vector<vector<char>>& board) {
        int n = board.size();//矩阵的行数
        int m = board[0].size();//矩阵中第一行的元素个数,既列数
        build(n, m, board);//记录每一个值为1的数据
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (board[i][j] == '1') {
                    if (j > 0 && board[i][j - 1] == '1') {
                        union(i, j, i, j - 1);//合并两个坐标进入一个集合
                    }
                    if (i > 0 && board[i - 1][j] == '1') {
                        union(i, j, i - 1, j);
                    }
                }
            }
        }
        return sets;//多少个集合,既岛屿
    }

private:
    static const int MAXSIZE = 100001;
    static int father[MAXSIZE];
    static int cols;
    static int sets;

    void build(int n, int m, vector<vector<char>>& board) {
        cols = m;
        sets = 0;
        for (int a = 0; a < n; a++) {
            for (int b = 0, index; b < m; b++) {
                if (board[a][b] == '1') {
                    index = indexe(a, b);
                    father[index] = index;将自己的父亲指向自己,既自己是个独立的集合
                    sets++;
                }
            }
        }
    }
    

    int indexe(int a, int b) {
        return a * cols + b;//计算该坐标的一维id
    }

    int find(int i) {
        if (i != father[i]) {
            father[i] = find(father[i]);//找到自己的集合的根节点,也就是这个集合用来连接下一个集合的最后一位
        }
        return father[i];
    }

    void union(int a, int b, int c, int d) {
        int fx = find(indexe(a, b));
        int fy = find(indexe(c, d));
        if (fx != fy) {
            father[fx] = fy;//连接二者
            sets--;
        }
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值