@@ -11,39 +11,56 @@ export const pathLongest = (
1111 source : string ,
1212 target : string
1313) : string [ ] => {
14- let longest : string [ ] = [ ] ;
15- const queue : string [ ] [ ] = [ [ source ] ] ;
16- const depthMap : Record < string , number > = {
17- [ source ] : 0 ,
18- } ;
14+ // Track the best (longest) depth at which we've visited each node
15+ const depthMap : Record < string , number > = { [ source ] : 0 } ;
16+ // Parent pointers keyed by "node" storing the parent on the longest known path
17+ const parentOf : Record < string , string | null > = { [ source ] : null } ;
18+ // Track visited nodes on the current BFS path to detect cycles
19+ // Each queue entry is [node, depth, Set of ancestors on this path]
20+ const queue : Array < [ string , number , Set < string > ] > = [ [ source , 0 , new Set ( [ source ] ) ] ] ;
21+ let longestDepth = - 1 ;
22+ let foundTarget = false ;
1923
2024 while ( queue . length ) {
21- const path = queue . shift ( ) ! ;
22- const node = path [ path . length - 1 ] ;
25+ const [ node , depth , ancestors ] = queue . shift ( ) ! ;
2326
2427 if ( node === target ) {
25- if ( path . length > longest . length ) {
26- longest = path ;
28+ if ( depth > longestDepth ) {
29+ longestDepth = depth ;
30+ foundTarget = true ;
31+ }
32+ continue ;
33+ }
34+
35+ const children = graph [ node ] ?. children || [ ] ;
36+ for ( const child of children ) {
37+ if ( ancestors . has ( child ) ) {
38+ logger . error ( 'graph' , `TIME TRAVELER! Cyclic relationship: ${ child } <-> ${ node } ` ) ;
39+ continue ;
40+ }
41+ if ( ! depthMap [ child ] ) depthMap [ child ] = 0 ;
42+ // only queue this child if it is a further distance than we have seen already
43+ if ( depthMap [ child ] < depth + 1 ) {
44+ depthMap [ child ] = depth + 1 ;
45+ parentOf [ child ] = node ;
46+ const childAncestors = new Set ( ancestors ) ;
47+ childAncestors . add ( child ) ;
48+ queue . push ( [ child , depth + 1 , childAncestors ] ) ;
2749 }
28- } else {
29- const children = graph [ node ] ?. children || [ ] ;
30- children . forEach ( ( child ) => {
31- if ( ! depthMap [ child ] ) depthMap [ child ] = 0 ;
32- if ( path . includes ( child ) ) {
33- logger . error ( 'graph' , `TIME TRAVELER! Cyclic relationship: ${ child } <-> ${ node } | ${ path . slice ( path . indexOf ( child ) ) . join ( ' -> ' ) } ` ) ;
34- return ;
35- }
36- // only queue this child if it is a further distance than we have seen already
37- // for this child relationship to the source
38- if ( depthMap [ child ] < path . length ) {
39- queue . push ( [ ...path , child ] ) ;
40- depthMap [ child ] = path . length ;
41- }
42- } ) ;
4350 }
4451 }
4552
46- return longest ;
53+ if ( ! foundTarget ) return [ ] ;
54+
55+ // Reconstruct path from parent pointers
56+ const path : string [ ] = [ ] ;
57+ let current : string | null = target ;
58+ while ( current !== null ) {
59+ path . push ( current ) ;
60+ current = parentOf [ current ] ?? null ;
61+ }
62+ path . reverse ( ) ;
63+ return path ;
4764} ;
4865
4966export default pathLongest ;
0 commit comments