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 ) ;
3
9
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 , [ ] ) ;
7
34
}
8
35
}
9
36
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 )
13
44
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 ;
17
49
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 ] ] ;
21
52
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 ;
26
60
}
27
61
}
28
62
29
- let visited = { } ; // 'false' = visited, ' true' = current path
30
- let res = [ ] ;
63
+ return true ;
64
+ } ;
31
65
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 )
35
70
}
71
+ }
72
+ } ;
36
73
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 ) ;
43
83
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 ) ;
46
97
}
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 '' ;
47
110
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 , [ ] ) ;
51
130
}
52
- } ) ;
131
+ }
53
132
54
- return res . reverse ( ) . join ( '' ) ;
133
+ return { graph , seen , buffer } ;
55
134
} ;
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