Tuesday, September 15, 2015

Leetcode: Alien Dictionary

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.
For example,
Given the following words in dictionary,
[
  "wrt",
  "wrf",
  "er",
  "ett",
  "rftt"
]
The correct order is: "wertf".
Note:
  1. You may assume all letters are in lowercase.
  2. If the order is invalid, return an empty string.
  3. There may be multiple valid order of letters, return any one of them is fine.
Understand the problem:
The problem can be solved by a topological sorting. First we construct the graph based on the ordering relationship. Then do a topological sorting, which return the correct order. 

Code (Java):
public class Solution {
    public String alienOrder(String[] words) {
        // Step 1: build the graph
        Map<Character, Set<Character>> graph = new HashMap<>();
        for (int i = 0; i < words.length; i++) {
            String curr = words[i];
            for (int j = 0; j < curr.length(); j++) {
                if (!graph.containsKey(curr.charAt(j))) {
                    graph.put(curr.charAt(j), new HashSet<Character>());
                }
            }
            
            if (i > 0) {
                connectGraph(graph, words[i - 1], curr);
            }
        }
        
        // Step 2: toplogical sorting
        StringBuffer sb = new StringBuffer();
        Map<Character, Integer> visited = new HashMap<Character, Integer>();
        
        Iterator it = graph.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            char vertexId = (char) pair.getKey();
            if (toplogicalSort(vertexId, graph, sb, visited) == false) {
                return "";
            }
        }
        
        return sb.toString();
    }
    
    private void connectGraph(Map<Character, Set<Character>> graph, String prev, String curr) {
        if (prev == null || curr == null) {
            return;
        }
        
        int len = Math.min(prev.length(), curr.length());
        
        for (int i = 0; i < len; i++) {
            char p = prev.charAt(i);
            char q = curr.charAt(i);
            if (p != q) {
                if (!graph.get(p).contains(q)) {
                    graph.get(p).add(q);
                }
                break;
            }
        }
    }
    
    private boolean toplogicalSort(char vertexId, Map<Character, Set<Character>> graph, StringBuffer sb, 
                                   Map<Character, Integer> visited) {
        if (visited.containsKey(vertexId)) {
            // visited
            if (visited.get(vertexId) == -1) {
                return false;
            }
            
            // already in the list
            if (visited.get(vertexId) == 1) {
                return true;
            }
        } else {
            // mark as visited
            visited.put(vertexId, -1);
        }
        
        Set<Character> neighbors = graph.get(vertexId);
        for (char neighbor : neighbors) {
            if (toplogicalSort(neighbor, graph, sb, visited) == false) {
                return false;
            }
        }
        
        sb.insert(0, vertexId);
        visited.put(vertexId, 1);
        
        return true;
    }
}

Update on 4/22/19: Topological sort using BFS
public class Solution {
    /**
     * @param words: a list of words
     * @return: a string which is correct order
     */
    public String alienOrder(String[] words) {
        // Write your code here
        if (words == null || words.length == 0) {
            return "";
        }
        
        // step 1: construct the graph
        //
        Map<Character, List<Character>> adjList = new HashMap<>();
        constructGraph(words, adjList);
        
        int numNodes = adjList.size();
        
        StringBuilder ans = new StringBuilder();
        
        // toplogical sorting
        //
        Map<Character, Integer> indegreeMap = new HashMap<>();
        for (Character node : adjList.keySet()) {
            indegreeMap.put(node, 0);
        }
        
        for (Character node : adjList.keySet()) {
            for (Character neighbor : adjList.get(node)) {
                int indegree = indegreeMap.get(neighbor);
                indegree += 1;
                indegreeMap.put(neighbor, indegree);
            }
        }
        
        Queue<Character> queue = new PriorityQueue<>();
        for (Character node : indegreeMap.keySet()) {
            if (indegreeMap.get(node) == 0) {
                queue.offer(node);
            }
        }
        
        while (!queue.isEmpty()) {
            char curNode = queue.poll();
            ans.append(curNode);
            
            for (char neighbor : adjList.get(curNode)) {
                int indegree = indegreeMap.get(neighbor);
                indegree -= 1;
                indegreeMap.put(neighbor, indegree);
                if (indegree == 0) {
                    queue.offer(neighbor);
                }
            }
        }
        
        if (ans.length() < numNodes) {
            return "";
        }
        
        return ans.toString();
    }
    
    private void constructGraph(String[] words, Map<Character, List<Character>> adjList) {
        // construct nodes
        //
        for (String word : words) {
            for (Character c : word.toCharArray()) {
                adjList.put(c, new ArrayList<>());
            }
        }
        
        // construct edges
        //
        for (int i = 1; i < words.length; i++) {
            String prev = words[i - 1];
            String curr = words[i];
            
            for (int j = 0; j < prev.length() && j < curr.length(); j++) {
                if (prev.charAt(j) != curr.charAt(j)) {
                    adjList.get(prev.charAt(j)).add(curr.charAt(j));
                    break;
                }
            }
        }
    }
}




No comments:

Post a Comment