LC 0269 [H] Alien Dictionary - ALawliet/algorithms GitHub Wiki
- build adjacency list of neighbors for a directed graph with count of indegrees, break after first char diff
- if no break then edge case to bail early if we get a prefix after a word (contradiction) because it cannot be decoded
- topological sort
class Solution:
def toposort(self, adj, indeg):
order = []
Q = deque([c for c in indeg if indeg[c] == 0])
while Q:
u = Q.popleft()
order.append(u)
for v in adj[u]:
indeg[v] -= 1
if indeg[v] == 0:
Q.append(v)
return order
def alienOrder(self, words: List[str]) -> str:
adj = defaultdict(set)
indeg = {c: 0 for w in words for c in w}
for w1, w2 in zip(words, words[1:]):
for c1, c2 in zip(w1, w2):
if c1 != c2:
if c2 not in adj[c1]:
adj[c1].add(c2)
indeg[c2] += 1
break
else:
if not len(w1) <= len(w2): return ''
order = self.toposort(adj, indeg)
if len(order) != len(indeg): return ''
return ''.join(order)
from queue import Queue
class Solution:
def alienOrder(self, words: List[str]) -> str:
# Step 0: create data structures + the indegree of each unique letter to 0.
neighbors = defaultdict(set)
indegree = Counter({c:0 for word in words for c in word})
# Step 1: We need to populate adjlist of neighbors and indegree.
# For each pair of adjacent words...
for w1, w2 in zip(words, words[1:]):
for c1, c2 in zip(w1, w2):
if c1 != c2:
if c2 not in neighbors[c1]:
neighbors[c1].add(c2)
indegree[c2] += 1
break # first diff
else: # Check that second word isn't a prefix of first because prefixes come first so if abc,ab can't find valid ordering
if not len(w1) <= len(w2): return ''
# Step 2: We need to repeatedly pick off nodes with an indegree of 0.
output = []
Q = Queue()
[Q.put(c) for c in indegree if indegree[c] == 0]
while not Q.empty():
node = Q.get()
output.append(node)
for neighbor in neighbors[node]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0:
Q.put(neighbor)
# If not all letters are in output, that means there was a cycle and so
# no valid ordering. Return '' as per the problem description.
if len(output) < len(indegree): return ''
# Otherwise, convert the ordering we found into a string and return it.
return ''.join(output)