1
+ // Runtime: 4875 ms (Top 5.9%) | Memory: 114.72 MB (Top 34.5%)
2
+
1
3
/**
2
4
* @param {number[] } edges
3
5
* @return {number }
4
6
*/
5
- var longestCycle = function ( edges ) {
6
- // visited array will be -1 if not visited or index of first visited node
7
- const visited = Array ( edges . length ) . fill ( - 1 )
8
- let ans = - 1
9
-
10
- for ( let i = 0 ; i < edges . length ; i ++ ) {
11
-
12
- // Since one node could be part of only one solution, only compute if it is not already visited.
13
- if ( visited [ i ] !== - 1 ) continue ;
14
-
15
- // detect cycle: check if node is already visited
16
- // if it was visited and the visited[i] === i,
17
- // it means we came to this node during this iteration
18
- // hence find the length
19
-
20
- let currNode = i
21
-
22
- while ( currNode !== - 1 ) {
23
- // if not already visited, mark as visited
24
- if ( visited [ currNode ] === - 1 ) {
25
- visited [ currNode ] = i
26
- currNode = edges [ currNode ]
27
- continue ;
28
- }
29
-
30
- // if already visited, and value is equal to current index
31
- // it means we came to node during this iteration, hence we found the cycle
32
- if ( visited [ currNode ] === i ) {
33
- // find the cycle length
34
- let currCycleLen = 1
35
- let cycleStartNode = currNode
36
- currNode = edges [ currNode ]
37
-
38
- // revisit all the nodes since first cycle node and note the length
39
- while ( currNode !== cycleStartNode ) {
40
- currCycleLen ++
41
- currNode = edges [ currNode ]
7
+ function getCycleTopology ( edges ) {
8
+ const indeg = new Array ( edges . length ) . fill ( 0 ) ;
9
+ const queue = [ ] ;
10
+ const map = { } ;
11
+ for ( const src in edges ) {
12
+ const des = edges [ src ]
13
+ if ( des >= 0 ) {
14
+ indeg [ des ] ++ ;
15
+ }
16
+ map [ src ] ? map [ src ] . push ( des ) : map [ src ] = [ des ]
17
+ }
18
+ for ( const node in indeg ) {
19
+ if ( indeg [ node ] === 0 ) {
20
+ queue . push ( node )
21
+ }
22
+ }
23
+ while ( queue . length > 0 ) {
24
+ const node = queue . shift ( ) ;
25
+ for ( const connectedNode of map [ node ] ) {
26
+ if ( connectedNode !== - 1 ) {
27
+ indeg [ connectedNode ] -- ;
28
+ if ( indeg [ connectedNode ] === 0 ) {
29
+ queue . push ( connectedNode ) ;
42
30
}
43
- ans = Math . max ( currCycleLen , ans )
44
31
}
45
- break ;
46
32
}
47
33
}
48
- // console.log(visited)
49
- return ans
50
- } ;
34
+ return indeg
35
+ }
36
+ class DisjointSet {
37
+ constructor ( n ) {
38
+ this . n = n ;
39
+ this . root = new Array ( n ) . fill ( 0 ) . map ( ( _ , i ) => i ) ;
40
+ this . rank = new Array ( n ) . fill ( 1 ) ;
41
+
42
+ }
43
+ find ( x ) {
44
+ if ( x === this . root [ x ] ) return x ;
45
+ return this . root [ x ] = this . find ( this . root [ x ] ) ;
46
+ }
47
+ union ( x , y ) {
48
+ const x_root = this . find ( x ) ;
49
+ const y_root = this . find ( y ) ;
50
+
51
+ if ( this . rank [ x_root ] < this . rank [ y_root ] ) {
52
+ [ this . rank [ x_root ] , this . rank [ y_root ] ] = [ this . rank [ y_root ] , this . rank [ x_root ] ] ;
53
+ }
54
+ this . root [ y_root ] = x_root ;
55
+ if ( this . rank [ x_root ] === this . rank [ y_root ] ) this . rank [ x_root ] ++ ;
56
+ }
57
+ _getGroupsComponentCounts ( ) {
58
+ let groups = { } ;
59
+ for ( const node of this . root ) {
60
+ const node_root = this . find ( node ) ;
61
+ groups [ node_root ] = groups [ node_root ] + 1 || 1
62
+ }
63
+ return groups
64
+ }
65
+ getLongestGroupComponentLength ( ) {
66
+ let longestLength = 1 ;
67
+ const lengths = this . _getGroupsComponentCounts ( ) ;
68
+ for ( const length of Object . values ( lengths ) ) {
69
+ if ( length > 1 ) {
70
+ longestLength = Math . max ( longestLength , length ) ;
71
+ }
72
+ }
73
+ return longestLength > 1 ? longestLength : - 1 ;
74
+ }
75
+ }
76
+ var longestCycle = function ( edges ) {
77
+ const djs = new DisjointSet ( edges . length ) ;
78
+ let res = - 1
79
+
80
+ // topology sort results topology array.
81
+ // component with greater than 0 is cyclic component.
82
+ // now we need to get groups of cycle since we can't distinguish each cycles with current datas.
83
+ const cycleComponent = getCycleTopology ( edges ) ;
84
+
85
+ //with edges info and cycle component data, we can now distinguish each cycle group by union finde
86
+ // because each cycle r independent with each other.
87
+ for ( const src in edges ) {
88
+ const des = edges [ src ] ;
89
+ if ( cycleComponent [ src ] && cycleComponent [ des ] ) {
90
+ djs . union ( src , des ) ;
91
+ }
92
+ }
93
+ res = djs . getLongestGroupComponentLength ( )
94
+ return res
95
+ } ;
96
+
0 commit comments