An interactive visualization of the Alien Dictionary problem. Watch how word comparisons derive ordering edges, build a character DAG, and topological sort produces the alien alphabet.
Topological Sort LeetCode 269 ↗ Hardwords from the alien language's dictionary, where the strings are
sorted lexicographically by the rules of this new language."".
If there are multiple valid orderings, return any of them.
fun alienOrder(words: Array<String>): String { val graph = mutableMapOf<Char, MutableSet<Char>>() val inDegree = mutableMapOf<Char, Int>() words.forEach { w -> w.forEach { c -> graph.putIfAbsent(c, mutableSetOf()); inDegree.putIfAbsent(c, 0) } } for (i in 0 until words.size - 1) { val w1 = words[i]; val w2 = words[i + 1] if (w1.length > w2.length && w1.startsWith(w2)) return "" // invalid for (j in 0 until minOf(w1.length, w2.length)) { if (w1[j] != w2[j]) { if (w2[j] !in graph[w1[j]]!!) { graph[w1[j]]!!.add(w2[j]) inDegree[w2[j]] = inDegree[w2[j]]!! + 1 } ; break } } } val queue = ArrayDeque(inDegree.filter { it.value == 0 }.keys) val result = StringBuilder() while (queue.isNotEmpty()) { val c = queue.removeFirst() result.append(c) for (nb in graph[c]!!) { inDegree[nb] = inDegree[nb]!! - 1 if (inDegree[nb] == 0) queue.addLast(nb) } } return if (result.length == graph.size) result.toString() else "" // cycle}
For each consecutive pair of words in the sorted list, we find the first position where the characters differ. This gives us an ordering constraint: the character in the first word comes before the character in the second word in the alien alphabet. If a longer word is a prefix of a shorter word that follows it, the input is invalid.
Each unique character becomes a node. Each ordering constraint becomes a directed edge. We also track the in-degree of each node (how many edges point into it). Characters with in-degree 0 have no prerequisites and can appear first.
We initialize a queue with all nodes that have in-degree 0. We repeatedly dequeue a node, add it to the result, and decrement the in-degree of all its neighbors. When a neighbor's in-degree reaches 0, it enters the queue. If the result contains all characters, we have a valid ordering. Otherwise, there is a cycle.
Where C is the total length of all words combined, and U is the number of unique characters (at most 26).
We scan each character at most once during word comparison, and the BFS processes each node and edge once.
Since the number of unique characters is bounded by 26, the graph operations are effectively O(1) in the alphabet size.