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,
Given the following words in dictionary,
[ "wrt", "wrf", "er", "ett", "rftt" ]
The correct order is:
"wertf"
.
Note:
- You may assume all letters are in lowercase.
- If the order is invalid, return an empty string.
- There may be multiple valid order of letters, return any one of them is fine.
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