【笔记】力扣 2316. 统计无向图中无法互相到达点对数——并查集, + 一种巧妙的求两两相乘之和的方法
中等
提示
给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。
请你返回 无法互相到达 的不同 点对数目 。
示例 1:

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

输入: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 <= 1050 <= edges.length <= 2 * 105edges[i].length == 20 <= ai, bi < nai != 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;
}
};
这里后面求和的地方非常巧妙
这是原本的求和思路,每块不连通节点区域,两两相乘

这是优化后的求和思路:
- 初始化 remainingNodes 为节点总数 n,代表初始未考虑的节点数。
- 遍历存储连通分量信息的 mem:
获取当前连通分量节点数 componentSize。
从 remainingNodes 中减去 componentSize,更新未考虑节点数。
将 componentSize 与 remainingNodes 相乘,得到当前连通分量与剩余节点组成的不连通节点对数,累加到 cnt。 - 遍历结束,cnt 即为图中不连通节点对总数。

浙公网安备 33010602011771号