Skip to content

Commit 6c10ca9

Browse files
solves #269: Alien Dictionary in java
1 parent 60a076d commit 6c10ca9

File tree

2 files changed

+48
-70
lines changed

2 files changed

+48
-70
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@
231231
| 266 | 🔒 [Palindrome Permutation](https://leetcode.com/problems/palindrome-permutation) | | |
232232
| 267 | 🔒 [Palindrome Permutation II](https://leetcode.com/problems/palindrome-permutation-ii) | | |
233233
| 268 | [Missing Number](https://leetcode.com/problems/missing-number) | [![Java](assets/java.png)](src/MissingNumber.java) [![Python](assets/python.png)](python/missing_number.py) | |
234+
| 269 | [Alien Dictionary](https://leetcode.com/problems/alien-dictionary) | [![Java](assets/java.png)](src/AlienDictionary.java) | |
234235
| 270 | 🔒 [Closest Binary Search Tree Value](https://leetcode.com/problems/closest-binary-search-tree-value) | | |
235236
| 271 | 🔒 [Encode and Decode Strings](https://leetcode.com/problems/encode-and-decode-strings) | | |
236237
| 274 | [H-Index](https://leetcode.com/problems/h-index) | [![Java](assets/java.png)](src/HIndex.java) | |

src/AlienDictionary.java

Lines changed: 47 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,68 @@
11
// https://leetcode.com/problems/alien-dictionary
2-
// T: O()
3-
// S: O()
2+
// C = length of all words added together
3+
// T: O(C)
4+
// S: O(1)
45

5-
import java.util.*;
6+
import java.util.ArrayList;
7+
import java.util.HashMap;
8+
import java.util.LinkedList;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.Queue;
612

713
public class AlienDictionary {
814
public String alienOrder(String[] words) {
9-
final Map<Character, Set<Character>> graph = createGraphFrom(words);
10-
return lexicographicallySmallest(graph);
11-
}
12-
13-
private static String lexicographicallySmallest(Map<Character, Set<Character>> graph) {
14-
final Map<Character, Integer> inDegree = computeInDegree(graph);
15-
final Queue<Character> queue = new LinkedList<>();
16-
final StringBuilder builder = new StringBuilder();
17-
add0InDegreeInQueue(queue, inDegree);
1815

19-
while (!queue.isEmpty()) {
20-
final char c = queue.poll();
21-
builder.append(c);
22-
for (char neighbour : graph.getOrDefault(c, new HashSet<>())) {
23-
inDegree.put(neighbour, inDegree.get(neighbour) - 1);
24-
if (inDegree.get(neighbour) == 0) {
25-
queue.add(neighbour);
26-
}
16+
// Step 0: Create data structures and find all unique letters.
17+
Map<Character, List<Character>> adjList = new HashMap<>();
18+
Map<Character, Integer> counts = new HashMap<>();
19+
for (String word : words) {
20+
for (char c : word.toCharArray()) {
21+
counts.put(c, 0);
22+
adjList.put(c, new ArrayList<>());
2723
}
28-
graph.remove(c);
2924
}
3025

31-
if (graph.isEmpty()) {
32-
return builder.toString();
33-
}
34-
return "";
35-
}
36-
37-
private static Map<Character, Set<Character>> createGraphFrom(String[] words) {
38-
final Map<Character, Set<Character>> graph = new HashMap<>();
39-
addAllLettersInGraph(graph, words);
40-
for (int i = 0 ; i < words.length ; i++) {
41-
for (int j = i + 1 ; j < words.length ; j++) {
42-
if (words[i].equals(words[j])) {
43-
continue;
44-
}
45-
final char[] charDiff = firstDifferentCharacter(words[i], words[j]);
46-
if (charDiff.length == 0) {
47-
continue;
48-
}
49-
final Set<Character> set = graph.getOrDefault(charDiff[0], new HashSet<>());
50-
set.add(charDiff[1]);
51-
graph.putIfAbsent(charDiff[0], set);
26+
// Step 1: Find all edges.
27+
for (int i = 0; i < words.length - 1; i++) {
28+
String word1 = words[i];
29+
String word2 = words[i + 1];
30+
// Check that word2 is not a prefix of word1.
31+
if (word1.length() > word2.length() && word1.startsWith(word2)) {
32+
return "";
5233
}
53-
}
54-
return graph;
55-
}
56-
57-
private static void addAllLettersInGraph(Map<Character, Set<Character>> graph, String[] words) {
58-
for (String word : words) {
59-
for (int i = 0 ; i < word.length() ; i++) {
60-
graph.putIfAbsent(word.charAt(i), new HashSet<>());
34+
// Find the first non match and insert the corresponding relation.
35+
for (int j = 0; j < Math.min(word1.length(), word2.length()); j++) {
36+
if (word1.charAt(j) != word2.charAt(j)) {
37+
adjList.get(word1.charAt(j)).add(word2.charAt(j));
38+
counts.put(word2.charAt(j), counts.get(word2.charAt(j)) + 1);
39+
break;
40+
}
6141
}
6242
}
63-
}
6443

65-
private static char[] firstDifferentCharacter(String s1, String s2) {
66-
for (int i = 0 ; i < s1.length() && i < s2.length() ; i++) {
67-
if (s1.charAt(i) != s2.charAt(i)) {
68-
return new char[] { s1.charAt(i), s2.charAt(i) };
44+
// Step 2: Breadth-first search.
45+
StringBuilder sb = new StringBuilder();
46+
Queue<Character> queue = new LinkedList<>();
47+
for (Character c : counts.keySet()) {
48+
if (counts.get(c).equals(0)) {
49+
queue.add(c);
6950
}
7051
}
71-
return new char[] {};
72-
}
73-
74-
private static Map<Character, Integer> computeInDegree(Map<Character, Set<Character>> graph) {
75-
final Map<Character, Integer> inDegree = new HashMap<>();
76-
for (Set<Character> set : graph.values()) {
77-
for (char c : set) {
78-
inDegree.put(c, inDegree.getOrDefault(c, 0) + 1);
52+
while (!queue.isEmpty()) {
53+
Character c = queue.remove();
54+
sb.append(c);
55+
for (Character next : adjList.get(c)) {
56+
counts.put(next, counts.get(next) - 1);
57+
if (counts.get(next).equals(0)) {
58+
queue.add(next);
59+
}
7960
}
8061
}
81-
return inDegree;
82-
}
8362

84-
private static void add0InDegreeInQueue(Queue<Character> queue, Map<Character, Integer> inDegree) {
85-
for (Map.Entry<Character, Integer> entry : inDegree.entrySet()) {
86-
if (entry.getValue() == 0) {
87-
queue.add(entry.getKey());
88-
}
63+
if (sb.length() < counts.size()) {
64+
return "";
8965
}
66+
return sb.toString();
9067
}
9168
}

0 commit comments

Comments
 (0)