LeetCode ยท #269

Alien Dictionary Solution

Given a sorted list of alien words, infer one valid character ordering. If the ordering is inconsistent, return an empty string.

01
Section One ยท Problem

Problem Statement

๐Ÿท๏ธ

Difficulty

Hard

๐Ÿ”—

LeetCode

Problem #269

๐Ÿ—๏ธ

Pattern

Topological sort + graph construction

The words are already sorted according to some unknown alphabet. Compare adjacent words to discover precedence rules between characters. Those rules form a directed graph; the alien alphabet is any topological order of that graph.

Example
Input: ["wrt", "wrf", "er", "ett", "rftt"] Output: "wertf" // From adjacent comparisons we learn: w < e, e < r, r < t, t < f
Most important edge case:
  • If a longer word appears before its exact prefix, like ["abc", "ab"], the dictionary order is impossible.
  • Return "" immediately.
02
Section Two ยท Approach 1

DFS Post-order Topological Sort

After building the character graph, run DFS with three-color cycle detection. When a node finishes, append it to an output list. Reverse that list at the end to get one valid character ordering.

Why it works

The first differing character between adjacent words determines the only ordering constraint we can safely infer from that pair. Once all constraints are collected, topological sort returns an order consistent with every edge.

Problem: DFS is correct, but Kahn's BFS is often easier to reason about for this problem because it directly exposes cycles through the final processed-character count. It also makes the "ready characters" concept very concrete.
03
Section Three ยท Approach 2

Kahn's BFS Topological Sort

Track every character that appears. Build directed edges only from the first mismatch in each adjacent word pair, and increment the destination's in-degree once per unique edge. Then queue every present character whose in-degree is 0.

  • Mark every character that appears in any word.
  • For adjacent words, find the first differing position. Add exactly one edge from word1[i] to word2[i].
  • If no difference exists and word1 is longer than word2, return empty string.
  • Run Kahn's BFS.
  • If the result length is less than the number of present characters, a cycle exists โ†’ return empty string.
๐Ÿ’ก Mental model: Each character is waiting behind a number of alphabet rules. Characters with zero incoming rules are currently legal to place next. Every time you place one, you remove its outgoing rules and may unlock more characters.
04
Section Four ยท Trace

Visual Walkthrough

Trace ["wrt", "wrf", "er", "ett", "rftt"].

Alien Dictionary โ€” graph construction + topo order
Compare "wrt" vs "wrf" โ†’ first mismatch at index 2: t โ†’ f Compare "wrf" vs "er" โ†’ first mismatch at index 0: w โ†’ e Compare "er" vs "ett" โ†’ first mismatch at index 1: r โ†’ t Compare "ett" vs "rftt" โ†’ first mismatch at index 0: e โ†’ r Order: w โ†’ e โ†’ r โ†’ t โ†’ f
05
Section Five ยท Implementation

Code โ€” Java & Python

Java โ€” build graph + Kahn's BFS
import java.util.*; class Solution { public String alienOrder(String[] words) { List<Set<Integer>> adj = new ArrayList<>(); for (int i = 0; i < 26; i++) adj.add(new HashSet<>()); boolean[] present = new boolean[26]; int presentCount = 0; for (String word : words) { for (char ch : word.toCharArray()) { int idx = ch - 'a'; if (!present[idx]) { present[idx] = true; presentCount++; } } } int[] indegree = new int[26]; for (int i = 0; i < words.length - 1; i++) { String a = words[i], b = words[i + 1]; if (a.length() > b.length() && a.startsWith(b)) return ""; int len = Math.min(a.length(), b.length()); for (int j = 0; j < len; j++) { char ca = a.charAt(j), cb = b.charAt(j); if (ca == cb) continue; int u = ca - 'a', v = cb - 'a'; if (adj.get(u).add(v)) indegree[v]++; break; } } Queue<Integer> queue = new ArrayDeque<>(); for (int i = 0; i < 26; i++) { if (present[i] && indegree[i] == 0) queue.offer(i); } StringBuilder order = new StringBuilder(); while (!queue.isEmpty()) { int u = queue.poll(); order.append((char) ('a' + u)); for (int v : adj.get(u)) { if (--indegree[v] == 0) queue.offer(v); } } return order.length() == presentCount ? order.toString() : ""; } }
Python โ€” adjacency from adjacent words
from collections import deque class Solution: def alienOrder(self, words: list[str]) -> str: present = [False] * 26 present_count = 0 for word in words: for ch in word: idx = ord(ch) - ord('a') if not present[idx]: present[idx] = True present_count += 1 adj = [set() for _ in range(26)] indegree = [0] * 26 for i in range(len(words) - 1): a, b = words[i], words[i + 1] if len(a) > len(b) and a.startswith(b): return "" for j in range(min(len(a), len(b))): if a[j] == b[j]: continue u = ord(a[j]) - ord('a') v = ord(b[j]) - ord('a') if v not in adj[u]: adj[u].add(v) indegree[v] += 1 break queue = deque(i for i in range(26) if present[i] and indegree[i] == 0) order = [] while queue: u = queue.popleft() order.append(chr(ord('a') + u)) for v in adj[u]: indegree[v] -= 1 if indegree[v] == 0: queue.append(v) return "".join(order) if len(order) == present_count else ""
06
Section Six ยท Analysis

Complexity Analysis

ApproachTimeSpaceTrade-off
DFS topological sortO(C + U + E)O(U + E)Elegant, but cycle handling is more subtle.
Kahn's BFS โ† optimalO(C + U + E)O(U + E)Directly builds the order and detects cycles via processed character count.
What do the symbols mean? C = total number of characters across all words, U = number of unique characters, E = precedence edges inferred from adjacent word pairs.
07
Section Seven ยท Edge Cases

Edge Cases & Pitfalls

CaseExpected behaviorWhy it matters
Single wordReturn all unique letters in that wordNo ordering constraints exist, but all present letters must appear.
Prefix invalid["abc","ab"] โ†’ ""A longer word cannot come before its own prefix.
CycleReturn ""Processed character count will be smaller than total present characters.
Duplicate edgeDo not increment indegree twiceUse a set per source character.
No mismatch in adjacent pairAdd no edgeOne word being a prefix of the next is valid if the shorter word comes first.
โš  Common Mistake: Comparing every pair of words instead of only adjacent pairs. The list is already sorted, so only adjacent pairs give safe, necessary ordering information. Non-adjacent comparisons can invent false edges.

โ† Back to Topological Sort