forked from neetcode-gh/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
0323-number-of-connected-components-in-an-undirected-graph.js
111 lines (88 loc) · 2.6 KB
/
0323-number-of-connected-components-in-an-undirected-graph.js
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
111
/**
* 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)
}
}
}