Skip to content

Commit

Permalink
Add Leetcode 269. Alien Dictionary
Browse files Browse the repository at this point in the history
  • Loading branch information
naco-siren committed May 16, 2020
1 parent 018c02f commit cbc11fe
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 0 deletions.
127 changes: 127 additions & 0 deletions src/leetcode/LC_269/Solution269.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package leetcode.LC_269;

import java.util.*;

/**
* 269. Alien Dictionary
*/
public class Solution269 {
String alienOrder(String[] words) {
// Adding all characters into a map
Map<Character, Node> nodes = new HashMap<>();
for (String word : words) {
for (int i = 0; i < word.length(); i++) {
final char ch = word.charAt(i);
if (!nodes.containsKey(ch))
nodes.put(ch, new Node(ch));
}
}

// Topological sort with a map of in-degrees
Map<Node, Integer> indegrees = new HashMap<>();

// Derive pairs in order by comparing word after word
for (int i = 1; i < words.length; i++) {
char[] pair = deriveCharPair(words[i - 1], words[i]);
if (pair == null)
return "";

if (pair.length == 0)
continue;

Node first = nodes.getOrDefault(pair[0], new Node(pair[0]));
Node second = nodes.getOrDefault(pair[1], new Node(pair[1]));

if (first.addChild(second))
indegrees.put(second, indegrees.getOrDefault(second, 0) + 1);

nodes.put(pair[0], first);
nodes.put(pair[1], second);
}

List<Node> order = extractTopologicalOrder(nodes, indegrees);

StringBuilder builder = new StringBuilder();
for (Node node : order)
builder.append(node.value);
return builder.toString();
}

char[] deriveCharPair(final String first, final String second) {
int i = 0;
for (; i < Math.min(first.length(), second.length()); i++) {
final char ch1 = first.charAt(i), ch2 = second.charAt(i);
if (ch1 == ch2)
continue;
return new char[]{ch1, ch2};
}

if (i == first.length())
return new char[]{};
else
return null;
}

/**
* Extract topological order of the characters from indegress map
* @param nodes
* @param indegrees
* @return
*/
List<Node> extractTopologicalOrder(Map<Character, Node> nodes, Map<Node, Integer> indegrees) {
// Find all 0-degree nodes
Queue<Node> queue = new LinkedList<>();
for (Map.Entry<Character, Node> entry : nodes.entrySet()) {
final Node node = entry.getValue();
if (!indegrees.containsKey(node))
queue.offer(node);
}

// There must be at least one zero in-degree node
final List<Node> order = new ArrayList<>();
if (queue.isEmpty())
return order;

// Perform topological sort
while (!queue.isEmpty()) {
Node node = queue.poll();
order.add(node);

for (Node child : node.children) {
Integer indegree = indegrees.get(child);
if (indegree == 1)
queue.offer(child);
indegrees.put(child, indegree - 1);
}
}

// All nodes' in-degrees must be distinct
if (order.size() != nodes.size())
return new LinkedList<>();
return order;
}

static class Node {
final char value;
final Set<Node> children;

Node(char value) {
this.value = value;
this.children = new HashSet<>();
}

boolean addChild(Node node) {
if (children.contains(node)) {
return false;
} else {
children.add(node);
return true;
}
}

@Override
public String toString() {
return "[" + value + "]";
}
}
}
60 changes: 60 additions & 0 deletions src/leetcode/LC_269/Solution269Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package leetcode.LC_269;

import org.junit.Test;

import static org.junit.Assert.*;

public class Solution269Test {

@Test
public void alienOrder_0() {
assertEquals("zx", new Solution269().alienOrder(new String[]{
"z",
"x"
}));
}

@Test
public void alienOrder_wtf_0() {
assertEquals("z", new Solution269().alienOrder(new String[]{
"z",
"z"
}));
}

@Test
public void alienOrder_wtf_0_0() {
assertEquals("ab", new Solution269().alienOrder(new String[]{
"ab",
"ab"
}));
}

@Test
public void alienOrder_1() {
assertEquals("", new Solution269().alienOrder(new String[]{
"abc",
"ab"
}));
}

@Test
public void alienOrder_2() {
assertEquals("wertf", new Solution269().alienOrder(new String[]{
"wrt",
"wrf",
"er",
"ett",
"rftt"
}));
}

@Test
public void alienOrder_invalid_1() {
assertEquals("", new Solution269().alienOrder(new String[]{
"z",
"x",
"z"
}));
}
}

0 comments on commit cbc11fe

Please sign in to comment.