forked from neetcode-gh/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
0684-redundant-connection.js
106 lines (84 loc) · 2.75 KB
/
0684-redundant-connection.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
/**
* https://leetcode.com/problems/redundant-connection/
* Time O((V)^2 + E) | Space O(V + E)
* @param {number[][]} edges
* @return {number[]}
*/
var findRedundantConnection = function (edges) {
const graph = new Array((1000 + 1)).fill().map(() => []);
for (const [ src, dst ] of edges) {
const hasNodes = (src in graph) && (dst in graph)
if (hasNodes && hasRedundantConnection(graph, src, dst)) return [ src, dst ];
graph[src].push(dst);
graph[dst].push(src);
}
}
const hasRedundantConnection = (graph, source, target, seen = new Set()) => {
if (seen.has(source)) return false
seen.add(source);
const isEqual = source === target
if (isEqual) return true;
return dfs(graph, source, target, seen);
}
const dfs = (graph, source, target, seen) => {
for (const neighbor of graph[source]) {
if (hasRedundantConnection(graph, neighbor, target, seen)) return true;
}
return false;
}
/**
* https://leetcode.com/problems/redundant-connection/
* Time O(V + E) | Space O(V + E)
* @param {number[][]} edges
* @return {number[]}
*/
var findRedundantConnection = function (edges) {
return new UnionFind(edges)
.redundantConnection;
};
class UnionFind {
constructor (edges) {
this.parent = new Array(edges.length + 1).fill().map((_, index) => index);
this.rank = new Array(edges.length + 1).fill(1);
this.redundantConnection = [ -1, -1 ];
this.search(edges);
}
search (edges) {
for (let [ src, dst ] of edges) {
const hasConnection = this.union(src, dst);
if (!hasConnection) return (this.redundantConnection = [ src, dst ]);
}
}
find (node, { parent } = this) {
let head = parent[node];
const isEqual = () => head === parent[head];
while (!isEqual()) {
const tail = parent[parent[head]];
this.compress(head, tail);
head = parent[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 false;
const isSrcGreater = rank[rootDst] < rank[rootSrc];
if (isSrcGreater) {
this.increaseRank(rootDst, rootSrc)
this.compress(rootSrc, rootDst)
}
const isDstGreater = rank[rootSrc] <= rank[rootDst];
if (isDstGreater) {
this.increaseRank(rootSrc, rootDst)
this.compress(rootDst, rootSrc)
}
return true;
}
}