-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Expand file tree
/
Copy path0323-number-of-connected-components-in-an-undirected-graph.js
More file actions
110 lines (87 loc) · 2.6 KB
/
0323-number-of-connected-components-in-an-undirected-graph.js
File metadata and controls
110 lines (87 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
* https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
* Time O(V + E) | Space O(V + E)
* @param {number} n
* @param {number[][]} edges
* @return {number}
*/
var countComponents = function (n, edges, count = 0) {
const { graph, visited } = buildGraph(n, edges);
for (const node in graph) {
if (hasPath(graph, node, visited)) count++;
}
return count;
};
const initGraph = (n) => ({
graph: new Array(n).fill().map(() => []),
visited: new Array(n).fill(false),
});
const buildGraph = (n, edges) => {
const { graph, visited } = initGraph(n);
for (const [src, dst] of edges) {
graph[src].push(dst);
graph[dst].push(src);
}
return { graph, visited };
};
const hasPath = (graph, current, visited) => {
if (visited[current]) return false;
visited[current] = current;
for (const neighbor of graph[current]) {
hasPath(graph, neighbor, visited);
}
return true;
};
/**
* https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
* Time O(E * a(N)) | Space O(V)
* @param {number} n
* @param {number[][]} edges
* @return {number}
*/
var countComponents = function (n, edges) {
return new UnionFind(n, edges).connectedComponents;
};
class UnionFind {
constructor(n, edges) {
((this.parent = new Array(n).fill().map((_, index) => index)),
(this.rank = new Array(n).fill(1)));
this.connectedComponents = n;
this.search(edges);
}
search(edges) {
for (const [src, dst] of edges) {
this.union(src, dst);
}
}
find(head, tail = head, { parent } = this) {
const isEqual = () => head === parent[head];
while (!isEqual()) {
head = parent[head];
}
this.compress(tail, head);
return head;
}
compress(tail, head, { parent } = this) {
parent[tail] = head;
}
increaseRank(head, tail, { rank } = this) {
rank[head] += rank[tail];
}
union(src, dst, { rank } = this) {
const [rootSrc, rootDst] = [this.find(src), this.find(dst)];
const hasCycle = rootSrc === rootDst;
if (hasCycle) return;
this.connectedComponents--;
const isGreater = rank[rootSrc] < rank[rootDst];
if (isGreater) {
this.increaseRank(rootDst, rootSrc);
this.compress(rootSrc, rootDst);
}
const isLess = rank[rootDst] <= rank[rootSrc];
if (isLess) {
this.increaseRank(rootSrc, rootDst);
this.compress(rootDst, rootSrc);
}
}
}