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 non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
Example 1:
Input: [ "wrt", "wrf", "er", "ett", "rftt" ] Output:"wertf"
Example 2:
Input: [ "z", "x" ] Output:"zx"
Example 3:
Input: [ "z", "x", "z" ] Output:""
Explanation: The order is invalid, so return""
.
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.
火星词典。
现有一种使用字母的全新语言,这门语言的字母顺序与英语顺序不同。
假设,您并不知道其中字母之间的先后顺序。但是,会收到词典中获得一个 不为空的 单词列表。因为是从词典中获得的,所以该单词列表内的单词已经 按这门新语言的字母顺序进行了排序。
您需要根据这个输入的列表,还原出此语言中已知的字母顺序。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/alien-dictionary
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路是拓扑排序,我这里给出的是BFS的解法。首先给每个牵涉到的字母都分别给一个入度1,同时需要计算这里一共牵涉到多少个不同的字母count。之后再次遍历input,这一次需要创建graph的边。创建的方式是用hashmap,分如下几个比较细节的步骤。
单词两两比较,发现第一个不同的字母之后,比如这个例子,
"wrt"和"wrf"
就把t当做key放入hashmap,map的value是一个hashset,再把f加入这个hashset,同时也把f的入度++,之后立即break(因为每两个单词之间其实只能最多得到两个字母之间的相对顺序)。照此遍历完所有的单词之后,根据入度表创建graph,还是把入度为1的字母加入queue。创建了graph之后,再来就是跟course schedule一样用BFS遍历每一条边,弹出queue的那一刻就将遍历到的字符append到结果集中;同时看这个字符是否在hashmap中,若在,也要去查看他对应的hashset里面有没有入度为1的字母,若有也要加入queue。最后如果res结果集的长度跟count不一致则返回空字符串。
时间O(V + E)
空间O(n) - 单词个数
Java实现
1 class Solution { 2 public static String alienOrder(String[] words) { 3 // corner case 4 if (words == null || words.length == 0) { 5 return ""; 6 } 7 8 // normal case 9 StringBuilder res = new StringBuilder(); 10 // 记录字典序 11 HashMap<Character, Set<Character>> map = new HashMap<>(); 12 int[] degree = new int[26]; 13 int count = 0; 14 for (String word : words) { 15 for (char c : word.toCharArray()) { 16 if (degree[c - 'a'] == 0) { 17 count++; 18 degree[c - 'a'] = 1; 19 } 20 } 21 } 22 23 // 两两单词比较字母的不同 24 for (int i = 0; i < words.length - 1; i++) { 25 char[] cur = words[i].toCharArray(); 26 char[] next = words[i + 1].toCharArray(); 27 // corner case, 会有非法情况 28 // 如果某个单词出现在他的前缀之前,则说明这个排序是不合法的 29 // ["abc", "ab"] 30 if (cur.length > next.length && words[i].startsWith(words[i + 1])) { 31 return ""; 32 } 33 34 // normal case, created the graph 35 int len = Math.min(cur.length, next.length); 36 for (int j = 0; j < len; j++) { 37 if (cur[j] != next[j]) { 38 if (!map.containsKey(cur[j])) { 39 map.put(cur[j], new HashSet<>()); 40 } 41 if (map.get(cur[j]).add(next[j])) { 42 degree[next[j] - 'a']++; 43 } 44 break; 45 } 46 } 47 } 48 49 Queue<Character> queue = new LinkedList<>(); 50 for (int i = 0; i < 26; i++) { 51 if (degree[i] == 1) { 52 queue.offer((char) ('a' + i)); 53 } 54 } 55 56 while (!queue.isEmpty()) { 57 char c = queue.poll(); 58 res.append(c); 59 if (map.containsKey(c)) { 60 for (char ch : map.get(c)) { 61 if (--degree[ch - 'a'] == 1) { 62 queue.offer(ch); 63 } 64 } 65 } 66 } 67 if (res.length() != count) { 68 return ""; 69 } 70 return res.toString(); 71 } 72 }
相关题目