Leetcode: 269. Alien Dictionary
Understand the problem
Given a sequence of words sorted lexicographically using unknown alphabetic order, return the alphabet's letters sorted in respect to the alphabet's rule.
Devise a plan
Modeling as a graph problem, letters are vertices and an edge \((u,v)\) means that the letter \(u\) comes before \(v\) in the unknown alphabet. If there are cycles in this graph then there is no way to build (discover) the alphabet because \(u, v_1, v_2, ..., v_k, u\) means that \(u\) comes before \(u\) what is impossible. Therefore, this is a Directed Graph. The problem become Pattern: Find topological order of vertices in a graph. Time complexity is \(O(n)\) and space complexity is \(O(n)\).
Carry out the plan
class Solution: def alienOrder(self, words: List[str]) -> str: A = {c: [] for w in words for c in w} for a, b in zip(words, words[1:]): if a == b: continue if a.startswith(b): return "" i = 0 while i < len(a) and i < len(b) and a[i] == b[i]: i += 1 if i < len(a) and i < len(b): A[a[i]].append(b[i]) deg = {c: 0 for c in A} for u in A: for v in A[u]: deg[v] += 1 queue = [u for u in A if deg[u] == 0] ans = [] for u in queue: ans.append(u) for v in A[u]: deg[v] -= 1 if deg[v] == 0: queue.append(v) if len(ans) != len(A): return "" return "".join(ans)
from typing import List class Solution: def alienOrder(self, words: List[str]) -> str: adj = {} for w1, w2 in zip(words, words[1:]): if len(w2) < len(w1) and w1.startswith(w2): return "" for c1, c2 in zip(w1, w2): if c1 != c2: adj.setdefault(c1, set()) adj[c1].add(c2) break NOT_VISITED = "NOT_VISITED" OPEN = "OPEN" CLOSED = "CLOSED" status = {c: NOT_VISITED for w in words for c in w} ans = [] def dfs(u): if status[u] == CLOSED: return True if status[u] == OPEN: return False status[u] = OPEN for v in adj.get(u, []): if not dfs(v): return False ans.append(u) status[u] = CLOSED return True for c in status: if status[c] == NOT_VISITED: if not dfs(c): return "" return "".join(reversed(ans)) assert Solution().alienOrder(["wrt","wrf","er","ett","rftt"]) == "wertf" assert Solution().alienOrder(["z","x"]) == "zx" assert Solution().alienOrder(["z","x","z"]) == "" assert Solution().alienOrder(["z","z"]) == "z" assert Solution().alienOrder(["abc","ab"]) == ""
Common mistakes
- Mistake: Missing edge case: \(abc,ab\).