1- let alienOrder = function ( words ) {
2- let graph = { } ;
1+ /**
2+ * BFS
3+ * https://leetcode.com/problems/alien-dictionary/
4+ * @param {string[] } words
5+ * @return {string }
6+ */
7+ var alienOrder = function ( words ) {
8+ const { graph, frequencyMap, queue, buffer } = buildGraph ( words ) ;
39
4- for ( let i = 0 ; i < words . length ; i ++ ) {
5- for ( let j = 0 ; j < words [ i ] . length ; j ++ ) {
6- graph [ words [ i ] [ j ] ] = new Set ( ) ;
10+ if ( ! canBuildGraph ( words , graph , frequencyMap ) ) return '' ;
11+
12+ queueSources ( queue , frequencyMap ) ;
13+ bfs ( queue , frequencyMap , graph , buffer ) ;
14+
15+ return ( frequencyMap . size <= buffer . length )
16+ ? buffer . join ( '' )
17+ : '' ;
18+ }
19+
20+ var initGraph = ( ) => ( {
21+ graph : new Map ( ) ,
22+ frequencyMap : new Map ( ) ,
23+ queue : new Queue ( ) ,
24+ buffer : [ ] ,
25+ } )
26+
27+ var buildGraph = ( words ) => {
28+ const { graph, frequencyMap, queue, buffer } = initGraph ( ) ;
29+
30+ for ( const word of words ) {
31+ for ( const char of word ) {
32+ frequencyMap . set ( char , 0 ) ;
33+ graph . set ( char , [ ] ) ;
734 }
835 }
936
10- for ( let i = 0 ; i < words . length - 1 ; i ++ ) {
11- let word1 = words [ i ] ;
12- let word2 = words [ i + 1 ] ;
37+ return { graph, frequencyMap, queue, buffer } ;
38+ } ;
39+
40+ var canBuildGraph = ( words , graph , frequencyMap ) => {
41+ for ( let index = 0 ; ( index < words . length - 1 ) ; index ++ ) {
42+ const [ word1 , word2 ] = [ words [ index ] , words [ ( index + 1 ) ] ] ;
43+ const minLength = Math . min ( word1 . length , word2 . length )
1344
14- if ( word1 . length > word2 . length && ( word1 + '' ) . startsWith ( word2 ) ) {
15- return '' ;
16- }
45+ const isWord1Longer = ( word2 . length < word1 . length ) ;
46+ const isPrefix = isWord1Longer && word1 . startsWith ( word2 ) ;
47+
48+ if ( isPrefix ) return false ;
1749
18- for ( let j = 0 ; j < Math . min ( word1 . length , word2 . length ) ; j ++ ) {
19- let c1 = word1 [ j ] ;
20- let c2 = word2 [ j ] ;
50+ for ( let j = 0 ; ( j < minLength ) ; j ++ ) {
51+ const [ char1 , char2 ] = [ word1 [ j ] , word2 [ j ] ] ;
2152
22- if ( c1 !== c2 ) {
23- graph [ c1 ] . add ( c2 ) ;
24- break ;
25- }
53+ const isEqual = ( char1 === char2 ) ;
54+ if ( isEqual ) continue ;
55+
56+ graph . get ( char1 ) . push ( char2 ) ;
57+ frequencyMap . set ( char2 , frequencyMap . get ( char2 ) + 1 ) ;
58+
59+ break ;
2660 }
2761 }
2862
29- let visited = { } ; // 'false' = visited, ' true' = current path
30- let res = [ ] ;
63+ return true ;
64+ } ;
3165
32- function dfs ( c ) {
33- if ( visited [ c ] ) {
34- return Boolean ( visited [ c ] ) ;
66+ const bfs = ( queue , frequencyMap , graph , buffer ) => {
67+ while ( ! queue . isEmpty ( ) ) {
68+ for ( let level = ( queue . size ( ) - 1 ) ; ( 0 <= level ) ; level -- ) {
69+ checkNeighbors ( queue , frequencyMap , graph , buffer )
3570 }
71+ }
72+ } ;
3673
37- visited [ c ] = 'true' ;
38- for ( let nei of graph [ c ] ) {
39- if ( dfs ( nei ) ) {
40- return true ;
41- }
42- }
74+ var checkNeighbors = ( queue , frequencyMap , graph , buffer ) => {
75+ const char = queue . dequeue ( ) ;
76+
77+ buffer . push ( char ) ;
78+
79+ for ( const next of graph . get ( char ) ) {
80+ const value = ( frequencyMap . get ( next ) - 1 ) ;
81+
82+ frequencyMap . set ( next , value ) ;
4383
44- visited [ c ] = 'false' ;
45- res . push ( c ) ;
84+ const isEmpty = ( frequencyMap . get ( next ) === 0 ) ;
85+ if ( ! isEmpty ) continue ;
86+
87+ queue . enqueue ( next ) ;
88+ }
89+ }
90+
91+ const queueSources = ( queue , frequencyMap ) => {
92+ for ( const [ key , value ] of frequencyMap ) {
93+ const isEmpty = ( frequencyMap . get ( key ) === 0 ) ;
94+ if ( ! isEmpty ) continue ;
95+
96+ queue . enqueue ( key ) ;
4697 }
98+ }
99+
100+ /**
101+ * DFS
102+ * https://leetcode.com/problems/alien-dictionary/
103+ * @param {string[] } words
104+ * @return {string }
105+ */
106+ var alienOrder = function ( words ) {
107+ const { graph, seen, buffer } = buildGraph ( words ) ;
108+
109+ if ( ! canBuildGraph ( words , graph ) ) return '' ;
47110
48- Object . keys ( graph ) . forEach ( ( c ) => {
49- if ( dfs ( c ) ) {
50- return '' ;
111+ for ( const [ char ] of graph ) {
112+ if ( ! dfs ( char , graph , seen , buffer ) ) return '' ;
113+ }
114+
115+ return buffer . reverse ( ) . join ( '' )
116+ }
117+
118+ var initGraph = ( ) => ( {
119+ graph : new Map ( ) ,
120+ seen : new Map ( ) ,
121+ buffer : [ ] ,
122+ } )
123+
124+ var buildGraph = ( words ) => {
125+ const { graph, seen, buffer } = initGraph ( ) ;
126+
127+ for ( const word of words ) {
128+ for ( const char of word ) {
129+ graph . set ( char , [ ] ) ;
51130 }
52- } ) ;
131+ }
53132
54- return res . reverse ( ) . join ( '' ) ;
133+ return { graph , seen , buffer } ;
55134} ;
135+
136+ var canBuildGraph = ( words , graph ) => {
137+ for ( let index = 0 ; ( index < words . length - 1 ) ; index ++ ) {
138+ const [ word1 , word2 ] = [ words [ index ] , words [ ( index + 1 ) ] ] ;
139+ const minLength = Math . min ( word1 . length , word2 . length )
140+
141+ const isWord1Longer = ( word2 . length < word1 . length ) ;
142+ const isPrefix = isWord1Longer && word1 . startsWith ( word2 ) ;
143+
144+ if ( isPrefix ) return false ;
145+
146+ for ( let j = 0 ; ( j < minLength ) ; j ++ ) {
147+ const [ char1 , char2 ] = [ word1 [ j ] , word2 [ j ] ] ;
148+
149+ const isEqual = ( char1 === char2 ) ;
150+ if ( isEqual ) continue ;
151+
152+ graph . get ( char1 ) . push ( char2 ) ;
153+
154+ break ;
155+ }
156+ }
157+
158+ return true ;
159+ } ;
160+
161+ const dfs = ( char , graph , seen , buffer ) => {
162+ if ( seen . has ( char ) ) return seen . get ( char ) ;
163+
164+ if ( ! backTrack ( char , graph , seen , buffer ) ) return false ;
165+
166+ buffer . push ( char ) ;
167+
168+ return true ;
169+ }
170+
171+ const backTrack = ( char , graph , seen , buffer ) => {
172+ seen . set ( char , false ) ;
173+ for ( const neighbor of graph . get ( char ) ) {
174+ if ( ! dfs ( neighbor , graph , seen , buffer ) ) return false ;
175+ }
176+ seen . set ( char , true ) ;
177+
178+ return true ;
179+ }
0 commit comments