There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
Note:
- You may assume all letters are in lowercase.
- You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
- If the order is invalid, return an empty string.
- There may be multiple valid order of letters, return any one of them is fine.
Test Cases
Examples 1:
Input:
[
"wrt",
"wrf",
"er",
"ett",
"rftt"
]
Output: "wertf"
Examples 2:
Input:
[
"z",
"x"
]
Output: "zx"
Examples 3:
Input:
[
"z",
"x",
"z"
]
Output: ""
Explanation: The order is invalid, so return "".
Constraints:
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] consists of only lowercase English letters.
Solution
class Solution {
public:
string alienOrder(vector<string>& A) {
unordered_map<int, unordered_set<int>> G;
int indegree[26] = {};
for (auto &s : A) {
for (char c : s) G[c - 'a'] = {};
}
for (int i = 1; i < A.size(); ++i) {
int j = 0;
for (; j < min(A[i - 1].size(), A[i].size()); ++j) {
if (A[i - 1][j] == A[i][j]) continue;
G[A[i - 1][j] - 'a'].insert(A[i][j] - 'a');
break;
}
if (j == A[i].size() && j < A[i - 1].size()) return "";
}
for (auto &[from, tos] : G) {
for (int to : tos) {
indegree[to]++;
}
}
queue<int> q;
for (int i = 0; i < 26; ++i) {
if (G.count(i) && indegree[i] == 0) q.push(i);
}
string ans;
while (q.size()) {
int u = q.front();
q.pop();
ans += u + 'a';
for (int v : G[u]) {
if (--indegree[v] == 0) q.push(v);
}
}
return ans.size() == G.size() ? ans : "";
}
};
class Solution {
// Returns the order of characters in the alien language, or "" if invalid
public String alienOrder(String[] words) {
// Adjacency matrix for graph representation
boolean[][] g = new boolean[26][26];
// Set of present characters
boolean[] s = new boolean[26];
int cnt = 0;
int n = words.length;
// Mark all unique characters and build graph edges
for (int i = 0; i < n - 1; ++i) {
for (char c : words[i].toCharArray()) {
if (cnt == 26) break;
c -= 'a';
if (!s[c]) {
++cnt;
s[c] = true;
}
}
int m = words[i].length();
for (int j = 0; j < m; ++j) {
if (j >= words[i + 1].length()) return ""; // prefix case
char c1 = words[i].charAt(j), c2 = words[i + 1].charAt(j);
if (c1 == c2) continue;
if (g[c2 - 'a'][c1 - 'a']) return ""; // cycle check
g[c1 - 'a'][c2 - 'a'] = true;
break;
}
}
// Mark unique characters in the last word
for (char c : words[n - 1].toCharArray()) {
if (cnt == 26) break;
c -= 'a';
if (!s[c]) {
++cnt;
s[c] = true;
}
}
// Calculate indegrees
int[] indegree = new int[26];
for (int i = 0; i < 26; ++i) {
for (int j = 0; j < 26; ++j) {
if (i != j && s[i] && s[j] && g[i][j]) {
++indegree[j];
}
}
}
// Topological sort using Kahn's algorithm
Deque<Integer> q = new LinkedList<>();
for (int i = 0; i < 26; ++i) {
if (s[i] && indegree[i] == 0) {
q.offerLast(i);
}
}
StringBuilder ans = new StringBuilder();
while (!q.isEmpty()) {
int t = q.pollFirst();
ans.append((char) (t + 'a'));
for (int i = 0; i < 26; ++i) {
if (i != t && s[i] && g[t][i]) {
if (--indegree[i] == 0) {
q.offerLast(i);
}
}
}
}
// If not all characters are used, return ""
return ans.length() < cnt ? "" : ans.toString();
}
}
import collections
class Node(object):
def __init__(self, val):
self.val = val
self.neighbors = []
def connect(self, node):
self.neighbors.append(node)
def getNbrs(self):
return self.neighbors
class Solution(object):
def alienOrder(self, words):
"""
:type words: List[str]
:rtype: str
"""
def dfs(root, graph, visited):
visited[root] = 1
for nbr in graph[root].getNbrs():
if visited[nbr.val] == 0:
if not dfs(nbr.val, graph, visited):
return False
elif visited[nbr.val] == 1:
return False
visited[root] = 2
self.ans += root
return True
self.ans = ""
graph = {}
visited = collections.defaultdict(int)
self.topNum = 0
for i in range(0, len(words) - 1):
a = words[i]
b = words[i + 1]
i = 0
while i < len(a) and i < len(b):
if a[i] != b[i]:
nodeA = nodeB = None
if a[i] not in graph:
nodeA = Node(a[i])
graph[a[i]] = nodeA
else:
nodeA = graph[a[i]]
if b[i] not in graph:
nodeB = Node(b[i])
graph[b[i]] = nodeB
else:
nodeB = graph[b[i]]
nodeA.connect(nodeB)
break
i += 1
if i < len(a) and i >= len(b):
return ""
for c in graph:
if visited[c] == 0:
if not dfs(c, graph, visited):
return ""
unUsedSet = set()
for word in words:
for c in word:
unUsedSet.add(c)
for c in unUsedSet:
if c not in graph:
self.ans += c
return self.ans[::-1]