LeetCode 323: Number of Connected Components in an Undirected Graph (Union-Find / Graph)
LeetCode 323Source: https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
English
Start with n isolated nodes, so components = n. For each edge (u,v), union their sets. If the union actually merges two different roots, decrement component count. At the end, the count is the answer.
Complexity
Time O((n+m) α(n)), space O(n).
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
private int[] p, r;
private int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
private boolean union(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return false;
if (r[ra] < r[rb]) p[ra] = rb;
else if (r[ra] > r[rb]) p[rb] = ra;
else { p[rb] = ra; r[ra]++; }
return true;
}
public int countComponents(int n, int[][] edges) {
p = new int[n];
r = new int[n];
for (int i = 0; i < n; i++) p[i] = i;
int comps = n;
for (int[] e : edges) if (union(e[0], e[1])) comps--;
return comps;
}
}func countComponents(n int, edges [][]int) int {
p := make([]int, n)
r := make([]int, n)
for i := range p { p[i] = i }
var find func(int) int
find = func(x int) int {
if p[x] != x { p[x] = find(p[x]) }
return p[x]
}
union := func(a, b int) bool {
ra, rb := find(a), find(b)
if ra == rb { return false }
if r[ra] < r[rb] { p[ra] = rb } else if r[ra] > r[rb] { p[rb] = ra } else { p[rb] = ra; r[ra]++ }
return true
}
comps := n
for _, e := range edges {
if union(e[0], e[1]) { comps-- }
}
return comps
}class Solution {
vector<int> p, r;
int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }
bool uni(int a,int b){
int ra=find(a), rb=find(b);
if(ra==rb) return false;
if(r[ra]<r[rb]) p[ra]=rb;
else if(r[ra]>r[rb]) p[rb]=ra;
else { p[rb]=ra; r[ra]++; }
return true;
}
public:
int countComponents(int n, vector<vector<int>>& edges) {
p.resize(n); r.assign(n,0);
iota(p.begin(), p.end(), 0);
int comps=n;
for(auto &e:edges) if(uni(e[0],e[1])) comps--;
return comps;
}
};class Solution:
def countComponents(self, n: int, edges: list[list[int]]) -> int:
parent = list(range(n))
rank = [0] * n
def find(x: int) -> int:
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(a: int, b: int) -> bool:
ra, rb = find(a), find(b)
if ra == rb:
return False
if rank[ra] < rank[rb]:
parent[ra] = rb
elif rank[ra] > rank[rb]:
parent[rb] = ra
else:
parent[rb] = ra
rank[ra] += 1
return True
comps = n
for a, b in edges:
if union(a, b):
comps -= 1
return compsvar countComponents = function(n, edges) {
const p = Array.from({ length: n }, (_, i) => i);
const r = Array(n).fill(0);
const find = (x) => {
if (p[x] !== x) p[x] = find(p[x]);
return p[x];
};
const union = (a, b) => {
let ra = find(a), rb = find(b);
if (ra === rb) return false;
if (r[ra] < r[rb]) p[ra] = rb;
else if (r[ra] > r[rb]) p[rb] = ra;
else { p[rb] = ra; r[ra]++; }
return true;
};
let comps = n;
for (const [a, b] of edges) if (union(a, b)) comps--;
return comps;
};中文
初始时有 n 个孤立点,所以连通分量数是 n。遍历每条边 (u,v) 做并查集合并;如果这条边把两个不同根节点连接起来,连通分量数减一。遍历结束后的数量就是答案。
复杂度分析
时间复杂度 O((n+m) α(n)),空间复杂度 O(n)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
private int[] p, r;
private int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
private boolean union(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return false;
if (r[ra] < r[rb]) p[ra] = rb;
else if (r[ra] > r[rb]) p[rb] = ra;
else { p[rb] = ra; r[ra]++; }
return true;
}
public int countComponents(int n, int[][] edges) {
p = new int[n];
r = new int[n];
for (int i = 0; i < n; i++) p[i] = i;
int comps = n;
for (int[] e : edges) if (union(e[0], e[1])) comps--;
return comps;
}
}func countComponents(n int, edges [][]int) int {
p := make([]int, n)
r := make([]int, n)
for i := range p { p[i] = i }
var find func(int) int
find = func(x int) int {
if p[x] != x { p[x] = find(p[x]) }
return p[x]
}
union := func(a, b int) bool {
ra, rb := find(a), find(b)
if ra == rb { return false }
if r[ra] < r[rb] { p[ra] = rb } else if r[ra] > r[rb] { p[rb] = ra } else { p[rb] = ra; r[ra]++ }
return true
}
comps := n
for _, e := range edges {
if union(e[0], e[1]) { comps-- }
}
return comps
}class Solution {
vector<int> p, r;
int find(int x){ return p[x]==x?x:p[x]=find(p[x]); }
bool uni(int a,int b){
int ra=find(a), rb=find(b);
if(ra==rb) return false;
if(r[ra]<r[rb]) p[ra]=rb;
else if(r[ra]>r[rb]) p[rb]=ra;
else { p[rb]=ra; r[ra]++; }
return true;
}
public:
int countComponents(int n, vector<vector<int>>& edges) {
p.resize(n); r.assign(n,0);
iota(p.begin(), p.end(), 0);
int comps=n;
for(auto &e:edges) if(uni(e[0],e[1])) comps--;
return comps;
}
};class Solution:
def countComponents(self, n: int, edges: list[list[int]]) -> int:
parent = list(range(n))
rank = [0] * n
def find(x: int) -> int:
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(a: int, b: int) -> bool:
ra, rb = find(a), find(b)
if ra == rb:
return False
if rank[ra] < rank[rb]:
parent[ra] = rb
elif rank[ra] > rank[rb]:
parent[rb] = ra
else:
parent[rb] = ra
rank[ra] += 1
return True
comps = n
for a, b in edges:
if union(a, b):
comps -= 1
return compsvar countComponents = function(n, edges) {
const p = Array.from({ length: n }, (_, i) => i);
const r = Array(n).fill(0);
const find = (x) => {
if (p[x] !== x) p[x] = find(p[x]);
return p[x];
};
const union = (a, b) => {
let ra = find(a), rb = find(b);
if (ra === rb) return false;
if (r[ra] < r[rb]) p[ra] = rb;
else if (r[ra] > r[rb]) p[rb] = ra;
else { p[rb] = ra; r[ra]++; }
return true;
};
let comps = n;
for (const [a, b] of edges) if (union(a, b)) comps--;
return comps;
};
Comments