-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Expand file tree
/
Copy path0684-redundant-connection.js
More file actions
108 lines (86 loc) · 2.76 KB
/
0684-redundant-connection.js
File metadata and controls
108 lines (86 loc) · 2.76 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
/**
* 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;
}
}