AlgoMaster Logo

Alien Dictionary

hardFrequencyUpdated September 21, 2026

Understanding the Problem

We are given a sorted dictionary of words in an alien language. The words follow the same lexicographic sorting rules we are familiar with, but the underlying alphabet has a different ordering of letters. Our job is to figure out what that ordering is.

A regular English dictionary works the same way. "apple" comes before "banana" because 'a' comes before 'b'. And "cat" comes before "cup" because when the first letters match ('c' == 'c'), we look at the second letter, and 'a' comes before 'u'. The alien dictionary follows the same comparison logic with a different letter ordering.

Comparing adjacent words in the list therefore extracts ordering rules. Each pair of adjacent words gives us at most one rule about which letter comes before which. Once we have all the rules, we need a total ordering of the letters that satisfies all of them, which is a topological sort problem.

Key Constraints:

  • 1 <= words.length <= 100 -> At most 100 words, meaning at most 99 pairs to compare. The number of edges in our graph is small.
  • 1 <= words[i].length <= 100 -> Each word can be up to 100 characters. Comparing two words takes O(L) where L is the shorter word's length.
  • words[i] consists of only lowercase English letters -> At most 26 unique characters. The graph has at most 26 nodes.

Approach 1: BFS Topological Sort (Kahn's Algorithm)

Intuition

Comparing adjacent words produces rules of the form "letter A comes before letter B". The problem then reduces to finding a total ordering that satisfies a set of pairwise constraints, and topological sort solves it.

First, compare each pair of adjacent words to extract edges. If word1 is "wrt" and word2 is "wrf", we compare character by character: 'w' == 'w', 'r' == 'r', 't' != 'f'. So we learn that 't' comes before 'f'. We stop at the first difference because the first differing position alone decides the lexicographic comparison; later characters carry no ordering information.

One edge case: if word1 is a prefix of word2 (e.g., "app" before "apple"), the pair is consistent and adds no edge. But if word2 is a prefix of word1 (e.g., "apple" before "app"), the input is invalid because a shorter string must come before a longer one when they share the same prefix.

After extracting all edges, we build a directed graph and run BFS-based topological sort (Kahn's algorithm). We track the in-degree of each node. Start with all nodes that have in-degree 0, process them, reduce the in-degree of their neighbors, and repeat. This also detects invalid input: a node on a cycle can never reach in-degree 0 because one of its predecessors is also stuck on the cycle, so cyclic nodes are never processed. If the result is missing characters, a cycle exists and we return an empty string.

Algorithm

  1. Collect all unique characters from all words into a set (these are the nodes of our graph).
  2. For each pair of adjacent words, find the first position where they differ. Add a directed edge from the character in word1 to the character in word2. If word1 is longer than word2 and word2 is a prefix of word1, return "" immediately.
  3. Build an adjacency list and compute in-degrees for all characters.
  4. Initialize a queue with all characters that have in-degree 0.
  5. Process the queue: dequeue a character, append it to the result, and decrement the in-degree of all its neighbors. If a neighbor's in-degree drops to 0, enqueue it.
  6. If the result contains all characters, return it. Otherwise, a cycle exists, so return "".

Visualization and Code

Loading animation...

The BFS approach is already optimal. Topological sort can also be implemented with DFS, which builds the ordering in reverse post-order and detects cycles through the recursion path itself rather than by counting processed nodes.

Approach 2: DFS Topological Sort

Intuition

DFS-based topological sort works differently from BFS. Instead of starting from nodes with no dependencies, we go deep into the graph and fully explore everything that must come after a character before placing that character in the ordering.

When DFS finishes a character (every character reachable from it has been processed), we append it to the result. At that moment, everything that must come after it is already in the list, so the list is built in reverse. Reversing it at the end produces a valid ordering.

Cycle detection uses three states per node: unvisited, visiting (currently on the DFS path), and visited (fully processed). If DFS reaches a node in the "visiting" state, the input contains a cycle and no valid ordering exists.

Algorithm

  1. Build the graph the same way as Approach 1 (compare adjacent words, extract edges).
  2. Create a state map: 0 = unvisited, 1 = visiting, 2 = visited.
  3. For each unvisited character, run DFS. In DFS, mark the node as "visiting", visit all neighbors recursively, then mark it as "visited" and add it to the result.
  4. If we ever visit a node that is currently "visiting", we have a cycle. Return "".
  5. Reverse the result to get the final ordering.

Visualization and Code

Loading animation...