269. Alien Dictionary
Question
There is a new alien language that uses the English alphabet. However, the order among the letters is unknown to you.
You are given a list of strings words
from the alien language's dictionary, where the strings in words
are sorted lexicographically by the rules of this new language.
Return a string of the unique letters in the new alien language sorted in lexicographically increasing order by the new language's rules. If there is no solution, return ""
. If there are multiple solutions, return any of them.
Algorithm
- Read question carefully. I firstly made a mistake. It said the words are sorted lexicographically. I'm not careful and think it's the characters in each word are sorted lexicographically.
- Others thing are much similar to the course schedule, a typical topological sorting question.
- Here you have no edges or graph to be traversed, so you have to construct by yourself. Compare adjacent words and find the first not equal character, then you get a dependency relation.
- A few things to notice is that:
- If the previous string is longer than the latter one and the latter one is also a prefix of the former, this violate the whole dictionary(all the words) are sorted lexicographically, and thus we return empty string.
- Once you a getting a different character, the following are useless and you should stop here when comparing.
- Ultimately, you should compare if the length of in degree(number of characters ) is equal to the size of result. If not, it mean we have come repeat character or we have a cycle here. Return an empty string is desired. Otherwise return a valid lexicographically sorting.
Code
class Solution {
public String alienOrder(String[] words) {
StringBuilder sb = new StringBuilder();
if (words == null || words.length == 0) {
return sb.toString();
}
Map<Character, Set<Character>> prerequisites = new HashMap<>();
Map<Character, Integer> indegree = new HashMap<>();
for (String word : words) {
for (Character ch : word.toCharArray()) {
indegree.put(ch, 0);
}
}
for (int i = 0; i < words.length - 1; i++) {
String word1 = words[i];
String word2 = words[i + 1];
int len = Math.min(word1.length(), word2.length());
if (word1.length() != word2.length() && word1.startsWith(word2)) return ""; // notice
for (int j = 0; j < len; j++) {
if (word1.charAt(j) != word2.charAt(j)) { // notice
Set<Character> set = prerequisites.getOrDefault(word1.charAt(j), new HashSet<>());
if (!set.contains(word2.charAt(j))) {
set.add(word2.charAt(j));
indegree.put(word2.charAt(j), indegree.get(word2.charAt(j)) + 1);
}
prerequisites.put(word1.charAt(j), set);
break; // notice
}
}
}
Queue<Character> queue = new LinkedList<>();
for (Character ch : indegree.keySet()) {
if (indegree.get(ch) == 0) {
queue.offer(ch);
}
}
while (!queue.isEmpty()) {
Character cur = queue.poll();
sb.append(cur);
if (prerequisites.containsKey(cur)) {
for (Character ch : prerequisites.get(cur)) {
indegree.put(ch, indegree.get(ch) - 1);
if (indegree.get(ch) == 0) {
queue.offer(ch);
}
}
}
}
return sb.length() == indegree.size() ? sb.toString() : ""; // notice
}
}