【笔记】力扣 2316. 统计无向图中无法互相到达点对数——并查集, + 一种巧妙的求两两相乘之和的方法

2316. 统计无向图中无法互相到达点对数

中等

提示

给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 aibi 之间有一条 无向 边。

请你返回 无法互相到达 的不同 点对数目

示例 1:

img

输入:n = 3, edges = [[0,1],[0,2],[1,2]]
输出:0
解释:所有点都能互相到达,意味着没有点对无法互相到达,所以我们返回 0 。

示例 2:

img

输入:n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]]
输出:14
解释:总共有 14 个点对互相无法到达:
[[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]]
所以我们返回 14 。

提示:

  • 1 <= n <= 105
  • 0 <= edges.length <= 2 * 105
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • ai != bi
  • 不会有重复边。

题解

class Solution {
public:
    vector<int> parent;
    int find(int x) {
        if (x!=parent[x]) {
            parent[x]=find(parent[x]);
        }
        return parent[x];
    }
    void unionSet(int x, int y) {
        int rootX=find(x);
        int rootY=find(y);
        if (rootX!=rootY) {
            parent[rootX]=rootY;
        }
    }
    long long countPairs(int n, vector<vector<int>>& edges) {
        parent.resize(n);
        for (int i=0;i<n;i++) {
            parent[i]=i;
        }
        for (int i=0;i<edges.size();i++) { //易错,不是n
            unionSet(edges[i][0],edges[i][1]);
        }
        unordered_map<int,int> mem;
        for (int i=0;i<n;i++) {
            mem[find(i)]++;
        }
        long long cnt=0;
        long long remain=n;
        for (auto m:mem) {
            remain-=m.second;
            cnt+=m.second*remain;
        }
        return cnt;
    }
};

这里后面求和的地方非常巧妙
这是原本的求和思路,每块不连通节点区域,两两相乘

这是优化后的求和思路:

  1. 初始化 remainingNodes 为节点总数 n,代表初始未考虑的节点数。
  2. 遍历存储连通分量信息的 mem:
    获取当前连通分量节点数 componentSize。
    从 remainingNodes 中减去 componentSize,更新未考虑节点数。
    将 componentSize 与 remainingNodes 相乘,得到当前连通分量与剩余节点组成的不连通节点对数,累加到 cnt。
  3. 遍历结束,cnt 即为图中不连通节点对总数。
posted @ 2025-03-30 00:19  ToFuture$  阅读(44)  评论(0)    收藏  举报