Alien Dictionary

hard graph topological sort

Problem

You are given a list of words from an alien language, already sorted by that language's unknown lexicographic order. Recover one valid ordering of the alphabet, or return "" if none exists.

Compare each adjacent pair of words. The first differing pair of characters (a, b) gives an edge a → b meaning "a comes before b". After collecting every edge, do a topological sort (Kahn's algorithm). If a cycle blocks completion, no valid order exists.

Inputwords = ["wrt","wrf","er","ett","rftt"]
Output"wertf"

from collections import deque, defaultdict

def alien_order(words):
    indeg = {c: 0 for w in words for c in w}
    graph = defaultdict(set)
    for w1, w2 in zip(words, words[:-1] + [None][1:] + words[1:]):
        if w2 is None: break
        if len(w1) > len(w2) and w1.startswith(w2):
            return ""
        for a, b in zip(w1, w2):
            if a != b:
                if b not in graph[a]:
                    graph[a].add(b)
                    indeg[b] += 1
                break
    q = deque(c for c in indeg if indeg[c] == 0)
    out = []
    while q:
        c = q.popleft()
        out.append(c)
        for nxt in graph[c]:
            indeg[nxt] -= 1
            if indeg[nxt] == 0:
                q.append(nxt)
    return "".join(out) if len(out) == len(indeg) else ""
function alienOrder(words) {
  const indeg = new Map();
  const graph = new Map();
  for (const w of words) for (const c of w) { if (!indeg.has(c)) { indeg.set(c, 0); graph.set(c, new Set()); } }
  for (let i = 0; i < words.length - 1; i++) {
    const w1 = words[i], w2 = words[i + 1];
    if (w1.length > w2.length && w1.startsWith(w2)) return "";
    for (let j = 0; j < Math.min(w1.length, w2.length); j++) {
      if (w1[j] !== w2[j]) {
        if (!graph.get(w1[j]).has(w2[j])) {
          graph.get(w1[j]).add(w2[j]);
          indeg.set(w2[j], indeg.get(w2[j]) + 1);
        }
        break;
      }
    }
  }
  const q = [];
  for (const [c, d] of indeg) if (d === 0) q.push(c);
  const out = [];
  while (q.length) {
    const c = q.shift();
    out.push(c);
    for (const nxt of graph.get(c)) {
      indeg.set(nxt, indeg.get(nxt) - 1);
      if (indeg.get(nxt) === 0) q.push(nxt);
    }
  }
  return out.length === indeg.size ? out.join("") : "";
}
class Solution {
    public String alienOrder(String[] words) {
        Map<Character, Integer> indeg = new HashMap<>();
        Map<Character, Set<Character>> graph = new HashMap<>();
        for (String w : words) for (char c : w.toCharArray()) {
            indeg.putIfAbsent(c, 0);
            graph.putIfAbsent(c, new HashSet<>());
        }
        for (int i = 0; i < words.length - 1; i++) {
            String w1 = words[i], w2 = words[i + 1];
            if (w1.length() > w2.length() && w1.startsWith(w2)) return "";
            int n = Math.min(w1.length(), w2.length());
            for (int j = 0; j < n; j++) {
                if (w1.charAt(j) != w2.charAt(j)) {
                    if (graph.get(w1.charAt(j)).add(w2.charAt(j)))
                        indeg.merge(w2.charAt(j), 1, Integer::sum);
                    break;
                }
            }
        }
        Deque<Character> q = new ArrayDeque<>();
        for (var e : indeg.entrySet()) if (e.getValue() == 0) q.add(e.getKey());
        StringBuilder out = new StringBuilder();
        while (!q.isEmpty()) {
            char c = q.poll();
            out.append(c);
            for (char nxt : graph.get(c)) {
                indeg.merge(nxt, -1, Integer::sum);
                if (indeg.get(nxt) == 0) q.add(nxt);
            }
        }
        return out.length() == indeg.size() ? out.toString() : "";
    }
}
string alienOrder(vector<string>& words) {
    unordered_map<char, int> indeg;
    unordered_map<char, set<char>> graph;
    for (auto& w : words) for (char c : w) { indeg[c]; graph[c]; }
    for (int i = 0; i + 1 < (int)words.size(); i++) {
        auto& w1 = words[i]; auto& w2 = words[i + 1];
        if (w1.size() > w2.size() && w1.substr(0, w2.size()) == w2) return "";
        int n = min(w1.size(), w2.size());
        for (int j = 0; j < n; j++) {
            if (w1[j] != w2[j]) {
                if (graph[w1[j]].insert(w2[j]).second) indeg[w2[j]]++;
                break;
            }
        }
    }
    queue<char> q;
    for (auto& [c, d] : indeg) if (d == 0) q.push(c);
    string out;
    while (!q.empty()) {
        char c = q.front(); q.pop();
        out.push_back(c);
        for (char nxt : graph[c]) {
            if (--indeg[nxt] == 0) q.push(nxt);
        }
    }
    return out.size() == indeg.size() ? out : "";
}
Time: O(N + Σ|w|) Space: O(1) (26-char alphabet)