[LeetCode] 269. Alien Dictionary 解题报告
2017-03-05 02:30
363 查看
There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list ofnon-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:
Given the following words in dictionary,
The correct order is:
Example 2:
Given the following words in dictionary,
The correct order is:
Example 3:
Given the following words in dictionary,
The order is invalid, so return
Note:
You may assume all letters are in lowercase.
You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
If the order is invalid, return an empty string.
There may be multiple valid order of letters, return any one of them is fine.
这一题是付费题,难度为hard,我个人觉得如果能看出来套路,就不难了。
首先,能想到拓扑排序(不要问我怎么想到的),这一题基本也就解决了一大半了。详细来说
,我们需要在脑海中构建一个图,图的节点就是字母,然后图的边是什么呢???这是一个很关键的地方,我一开始就搞错了 ,我感觉也是题目故意不交代清楚。
我一开始以为单词内的 字母要按顺序排,因此图的边就是一个单词内的字母之间的顺序,后来发现example1,就不符合这个规律。(真的是写完才发现的,特别麻烦。)
实际上,边是按照相邻单词之间不同字母的顺序来生成的,比如“abc”,“abd”,两个单词相邻,依次比较单词的各个字母,找到第一个不同的,也就是cd,那么c->d就形成一个边。以此类推比较完所有相邻的单词即可。(在本题中,遍历两个字符串中较小的长度,如果没有不同的字符,则忽略)
具体方法:
生成三个数组,1.int[26]存储不同节点的入度(实际上这里应该使用最小堆,但是由于只有26个字母,用数组效率更高),2.一个存储边对边数量int[26][26](实际上这里就是存储图的,用的是邻接矩阵方式存储图,而不是邻接链表,因为只有26个字母,所以很有限),3.int[26]第三个数组用来存储字母的出现顺序,用来应对在出现多种拓扑排序的结果时,用来确定哪个字母放在前面的;
初始化数组1,所有的值为-1,将出现了的字符置为0;并记录字符出现的顺序到数组3;获取相邻字符串的第一个不同字符,作为边,记录到数组2,当出现一个边时,还要对入度数组1对应的节点的数量++;(这一步实际上就是拓扑排序的准备工作,图结构和入度最小堆的构造)
拓扑排序。(将入度为0的节点取出以后,要将数组1中当前位置的值置为-1。假如出现多个入度为0的节点,则使用数组3进行排序)
检查入度数组,是否所有的值都为-1,如果不是则说明图中有环,输出为“”,否则输出结果。(这一步实际上是拓扑排序的收尾工作)
这里简单介绍一下拓扑排序的基本原理:选取一个入度为0的节点(入度数组1),将它加入结果队列list,并在邻接矩阵中去掉以该点为出度的所有边,并且在入度数组1中对应位置--。再选取入度为0的节点,直到所有节点都入度为0,输出list即可。(假如最后发现存在节点入度不为0的节点,说明图中有环,返回空。)
图示:
lexicographically by the rules of this new language. Derive the order of letters in this language.
Example 1:
Given the following words in dictionary,
[ "wrt", "wrf", "er", "ett", "rftt" ]
The correct order is:
"wertf".
Example 2:
Given the following words in dictionary,
[ "z", "x" ]
The correct order is:
"zx".
Example 3:
Given the following words in dictionary,
[ "z", "x", "z" ]
The order is invalid, so return
"".
Note:
You may assume all letters are in lowercase.
You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
If the order is invalid, return an empty string.
There may be multiple valid order of letters, return any one of them is fine.
这一题是付费题,难度为hard,我个人觉得如果能看出来套路,就不难了。
首先,能想到拓扑排序(不要问我怎么想到的),这一题基本也就解决了一大半了。详细来说
,我们需要在脑海中构建一个图,图的节点就是字母,然后图的边是什么呢???这是一个很关键的地方,我一开始就搞错了 ,我感觉也是题目故意不交代清楚。
我一开始以为单词内的 字母要按顺序排,因此图的边就是一个单词内的字母之间的顺序,后来发现example1,就不符合这个规律。(真的是写完才发现的,特别麻烦。)
实际上,边是按照相邻单词之间不同字母的顺序来生成的,比如“abc”,“abd”,两个单词相邻,依次比较单词的各个字母,找到第一个不同的,也就是cd,那么c->d就形成一个边。以此类推比较完所有相邻的单词即可。(在本题中,遍历两个字符串中较小的长度,如果没有不同的字符,则忽略)
具体方法:
生成三个数组,1.int[26]存储不同节点的入度(实际上这里应该使用最小堆,但是由于只有26个字母,用数组效率更高),2.一个存储边对边数量int[26][26](实际上这里就是存储图的,用的是邻接矩阵方式存储图,而不是邻接链表,因为只有26个字母,所以很有限),3.int[26]第三个数组用来存储字母的出现顺序,用来应对在出现多种拓扑排序的结果时,用来确定哪个字母放在前面的;
初始化数组1,所有的值为-1,将出现了的字符置为0;并记录字符出现的顺序到数组3;获取相邻字符串的第一个不同字符,作为边,记录到数组2,当出现一个边时,还要对入度数组1对应的节点的数量++;(这一步实际上就是拓扑排序的准备工作,图结构和入度最小堆的构造)
拓扑排序。(将入度为0的节点取出以后,要将数组1中当前位置的值置为-1。假如出现多个入度为0的节点,则使用数组3进行排序)
检查入度数组,是否所有的值都为-1,如果不是则说明图中有环,输出为“”,否则输出结果。(这一步实际上是拓扑排序的收尾工作)
这里简单介绍一下拓扑排序的基本原理:选取一个入度为0的节点(入度数组1),将它加入结果队列list,并在邻接矩阵中去掉以该点为出度的所有边,并且在入度数组1中对应位置--。再选取入度为0的节点,直到所有节点都入度为0,输出list即可。(假如最后发现存在节点入度不为0的节点,说明图中有环,返回空。)
图示:
public class Solution { private final static int NUM = 26; int[] nArrInDegreeNum; int[][] nArrEdges; int[] nArrOrders; public String alienOrder(String[] words) { nArrInDegreeNum = new int[NUM];// store number of indegree, like // min heap // init all to -1, which means there is no such element for (int i = 0; i < NUM; i++) { nArrInDegreeNum[i] = -1; } nArrEdges = new int[26][26];// store edge nArrOrders = new int[26];// for the order of alphabet int nOrder = 1; // init all character appeared to 0, and decide the order of alph for (String string : words) { // if it appears and =-2, set it = -1 for (char c : string.toCharArray()) { if (nArrInDegreeNum[c - 'a'] == -1) { nArrInDegreeNum[c - 'a'] = 0; } if (nArrOrders[c - 'a'] == 0) { nArrOrders[c - 'a'] = nOrder; nOrder++; } } } // compare the neighbor strings, and find the first different char for (int index = 0; index < words.length; index++) { if (index < words.length - 1) { findFirstDifferentChar(words[index], words[index + 1]); } } // top sort StringBuilder sb = new StringBuilder(); topologicalSorting(sb); // judge whether all degree is -1, if not return "" for (int i = 0; i < NUM; i++) { if (nArrInDegreeNum[i] != -1) { return ""; } } return sb.toString(); } private void topologicalSorting(StringBuilder sb) { boolean bFind = true; LinkedList<Integer> llFind = new LinkedList<>(); while (bFind) { bFind = false; for (int i = 0; i < NUM; i++) { if (nArrInDegreeNum[i] == 0) { bFind = true; llFind.add(i); nArrInDegreeNum[i] = -1; } } // if find the indegree==0 if (bFind) { // for two same chars, sort as its appeared order Collections.sort(llFind, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return nArrOrders[o1] - nArrOrders[o2]; } }); for (Integer integer : llFind) { char c = (char) ('a' + integer); sb.append(c); for (int i = 0; i < NUM; i++) { if (nArrEdges[integer][i] > 0) { nArrInDegreeNum[i] -= nArrEdges[integer][i]; nArrEdges[integer][i] = 0; } } } llFind.clear(); } } } private void findFirstDifferentChar(String str1, String str2) { char[] c1 = str1.toCharArray(); char[] c2 = str2.toCharArray(); int nLength = Math.min(c1.length, c2.length); for (int i = 0; i < nLength; i++) { if (c1[i] != c2[i]) { nArrInDegreeNum[c2[i] - 'a']++;// indegree num ++ nArrEdges[c1[i] - 'a'][c2[i] - 'a']++;// edge ++ break; } } } }
相关文章推荐
- [Leetcode] 179. Largest Number 解题报告
- [leetcode] 244. Shortest Word Distance II 解题报告
- [Leetcode] 81. Search in Rotated Sorted Array II 解题报告
- [LeetCode] Interleaving String 解题报告
- [Leetcode] 190. Reverse Bits 解题报告
- 【LeetCode】Largest Number 解题报告
- Leetcode 421. Maximum XOR of Two Numbers in an Array 最大Xor和 解题报告【待理解】
- [LeetCode] Plus One 解题报告
- [Leetcode] 311. Sparse Matrix Mult 4000 iplication 解题报告
- [LeetCode] Pow(x, n) 解题报告
- [Leetcode] 481. Magical String 解题报告
- [Leetcode] 483. Smallest Good Base 解题报告
- [Leetcode] 115. Distinct Subsequences 解题报告
- leetcode解题报告(13):K-diff Pairs in an Array
- LeetCode解题报告:LRU Cache
- LeetCode-Lowest Common Ancestor of a Binary Search Tree-解题报告
- Leetcode #49. Group Anagrams 变位词组合 解题报告
- [Leetcode] 767. Reorganize String 解题报告
- [Leetcode] 659. Split Array into Consecutive Subsequences 解题报告
- [Leetcode] 496. Next Greater Element I 解题报告