[并查集]并查集应用之省份数量

2021-02-15  本文已影响0人  铜炉

前言

经过并查集的升级路线一二三四之后,我们现在得到了一个相对来说比较完美的并查集数据结构,从本篇开始应用这个并查集为我们解决实际的算法问题。

省份数量

力扣547题
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。

题目分析

题目中需要计算的省份数量,实际上就是并查集的森林中树的数量,好在我们在并查集结构中已经使用count来标记了并查集中不同树的数量,所以,我们将链接的城市合并后,最终返回并查集中的count值即可。

题目步骤分解

1、构建并查集;
2、n*n矩阵,n代表着分量的数量,初始化并查集的时候,分量个数传入n;
3、遍历二维矩阵,如果对应值是1,就合并两个分量;
4、遍历结束后,返回并查集的count;

书写代码

并查集的准备

class QuickUnionUnionFind {

    // 存储连分量
    protected int[] id;
    // 当前并查集不同的连通分量总数
    protected int count;
    
    public QuickUnionUnionFind(int n) {
        // 初始化时,没个分量互不连通
        this.count = n;
        // 初始化一个容纳全量分量的数组
        this.id = new int[n];
        for (int i = 0; i < n; i++) {
            // 没个分量初始值指向自身
            id[i] = i;
        }
    }

    void union(int p, int q) {
        // 找到p的标识
        int pId = find(p);
        // 找到q的标识
        int qId = find(q);

        // 如果两个标识相等,代表已经合并
        if (pId == qId) return;

        // 如果不相等,直接让分量q的标识指向p
        id[pId] = qId;
        // 每次合并操作,会降低一个不同分量组
        count--;
    }

    int find(int p) {
        // 沿着标识路径一路寻找,直到找到树的标识
        while (p != id[p]) p = id[p];
        return p;
    }
}

算法代码

class Solution {
    public int findCircleNum(int[][] isConnected) {
        // n为分量总数
        int n = isConnected.length;
        QuickUnionUnionFind quuf = new QuickUnionUnionFind(n);

        for (int i = 0; i < isConnected.length; i++) {
            int[] row = isConnected[i];
            for (int k = i; k < row.length; k++) {
                
                if (isConnected[i][k] == 1) {
                    // 如果矩阵值为1,代表连通,需要合并
                    quuf.union(i, k);
                }
            }
        }

        // 返回树的个数
        return quuf.count;

    }
}
上一篇下一篇

猜你喜欢

热点阅读