package com.interview.graph;
import java.util.*;
/**
* 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 words from the dictionary, where words are sorted
* lexicographically by the rules of this new language. Derive the order of letters in this language.
*
* https://leetcode.com/problems/alien-dictionary/
*/
public class AlientDictionary {
public String alienOrder(String[] words) {
Set<Character> allCharacters = new HashSet<>();
Map<Character, Set<Character>> graph = buildGraph(words, new HashMap<>(), allCharacters);
Deque<Character> stack = new LinkedList<>();
Set<Character> visited = new HashSet<>();
Set<Character> dfs = new HashSet<>();
for (char ch : allCharacters) {
if (topSortUtil(ch, stack, visited, dfs, graph)) {
return "";
}
}
StringBuffer buff = new StringBuffer();
while (!stack.isEmpty()) {
buff.append(stack.pollFirst());
}
return buff.toString();
}
private boolean topSortUtil(char vertex, Deque<Character> stack, Set<Character> visited, Set<Character> dfs, Map<Character, Set<Character>> graph) {
if (visited.contains(vertex)) {
return false;
}
visited.add(vertex);
dfs.add(vertex);
Set<Character> set = graph.get(vertex);
if (set != null) {
for (char neighbor : set) {
if (dfs.contains(neighbor)) {
return true;
}
if (topSortUtil(neighbor, stack, visited, dfs, graph)) {
return true;
}
}
}
dfs.remove(vertex);
stack.offerFirst(vertex);
return false;
}
/**
* degree is only used for BFS. Not for DFS.
*/
private Map<Character, Set<Character>> buildGraph(String words[], Map<Character, Integer> degree, Set<Character> allCharacters) {
getAllChars(words, degree, allCharacters);
Set<Character> all = new HashSet<>(allCharacters);
Map<Character, Set<Character>> graph = new HashMap<>();
for (int i = 0; i < words.length - 1; i++) {
String nextWord = words[i + 1];
for (int k = 0; k < Math.min(words[i].length(), nextWord.length()); k++) {
if (words[i].charAt(k) != nextWord.charAt((k))) {
all.remove(words[i].charAt(k));
Set<Character> set = graph.get(words[i].charAt(k));
if (set == null) {
set = new HashSet<>();
graph.put(words[i].charAt(k), set);
}
set.add(nextWord.charAt(k));
degree.compute(nextWord.charAt(k), (key, count) -> count + 1);
break;
}
}
}
for (char ch : all) {
graph.put(ch, null);
}
return graph;
}
private void getAllChars(String words[], Map<Character, Integer> degree, Set<Character> allCharacters) {
for (String word : words) {
for (char ch : word.toCharArray()) {
allCharacters.add(ch);
degree.computeIfAbsent(ch, key -> 0);
}
}
}
public String alienOrder1(String words[]) {
Map<Character, Integer> degree = new HashMap<>();
Map<Character, Set<Character>> graph = buildGraph(words, degree, new HashSet<>());
Queue<Character> zeroDegreeNodes = new LinkedList<>();
for (Map.Entry<Character, Integer> entry : degree.entrySet()) {
if (entry.getValue() == 0) {
zeroDegreeNodes.offer(entry.getKey());
}
}
StringBuilder result = new StringBuilder();
while (!zeroDegreeNodes.isEmpty()) {
char vertex = zeroDegreeNodes.poll();
result.append(vertex);
Set<Character> neighbors = graph.get(vertex);
if (neighbors != null) {
for (char neighbor : graph.get(vertex)) {
int count = degree.get(neighbor);
count--;
if (count == 0) {
zeroDegreeNodes.offer(neighbor);
} else {
degree.put(neighbor, count);
}
}
}
graph.remove(vertex);
}
return graph.size() > 0 ? "" : result.toString();
}
public static void main(String args[]) {
AlientDictionary ad = new AlientDictionary();
String[] words1 = {"zy","zx"};
String[] words = {"wrt", "wrf", "er", "ett", "rftt"};
String[] words2 = {"wrtkj","wrt"};
String result = ad.alienOrder1(words2);
System.out.print(result);
//w -> e
// e -> r
//t -> f
//r -> t
//
}
}