class Solution {
Map<Character, Set<Character>> adjList;
Map<Character, Set<Character>> revList;
Map<Character, Integer> degrees;
private boolean createEdges(String left, String right) {
int minLen = Math.min(left.length(), right.length());
for (int i = 0; i < minLen; i++) {
char first = left.charAt(i), second = right.charAt(i);
if (first != second) {
Set<Character> edges = this.adjList.get(first);
edges.add(second);
this.adjList.put(first, edges);
Set<Character> revEdges = this.revList.get(second);
revEdges.add(first);
this.revList.put(second, revEdges);
return true;
}
}
return (left.length() <= right.length());
}
private void initialize(String[] words) {
int n = words.length;
this.adjList = new HashMap<>();
this.revList = new HashMap<>();
this.degrees = new HashMap<>();
for (int i = 0; i < n; i++) {
for (char c : words[i].toCharArray()) {
this.adjList.put(c, new HashSet<>());
this.revList.put(c, new HashSet<>());
this.degrees.put(c, 0);
}
}
}
private boolean createEdges(String[] words) {
int n = words.length;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (createEdges(words[i], words[j]) == false) return false;
}
}
return true;
}
private void createDegrees() {
for (char c : this.adjList.keySet()) {
this.degrees.put(c, this.adjList.get(c).size());
}
}
private List<Character> topologicalSort() {
Queue<Character> queue = new LinkedList<>();
Set<Character> taken = new HashSet<>();
List<Character> ordering = new ArrayList<>();
for (char c : this.degrees.keySet()) {
if (this.degrees.get(c) == 0) {
queue.add(c);
}
}
if (queue.isEmpty()) {
return null;
}
while (!queue.isEmpty()) {
int qSize = queue.size();
for (int i = 0; i < qSize; i++) {
char removed = queue.remove();
ordering.add(removed);
taken.add(removed);
for (char neighbor : this.revList.get(removed)) {
int degree = this.degrees.get(neighbor);
degree--;
if (degree == 0) queue.add(neighbor);
this.degrees.put(neighbor, degree);
}
}
}
if (ordering.size() < this.revList.size()) {
return null;
}
return ordering;
}
private String getString(List<Character> ordering) {
StringBuilder bld = new StringBuilder();
for (char c : ordering) bld.append(c);
return bld.reverse().toString();
}
public String alienOrder(String[] words) {
initialize(words);
if (createEdges(words) == false) return "";
createDegrees();
List<Character> ordering = topologicalSort();
if (ordering == null) return "";
return getString(ordering);
}
}