题目
现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。
给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。
请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 “” 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。
字符串 s 字典顺序小于 字符串 t 有两种情况:
在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。
如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。示例 1:
输入:words = [“wrt”,”wrf”,”er”,”ett”,”rftt”]
输出:”wertf”示例 2:
输入:words = [“z”,”x”]
输出:”zx”示例 3:
输入:words = [“z”,”x”,”z”]
输出:””
解释:不存在合法字母顺序,因此返回 “” 。提示:
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] 仅由小写英文字母组成来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/Jf1JuT
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
虽然是hard难度,但思路比较好想。
对于输入的单词数组,对于相邻的两个字符串两两比较,得到关于字母的先后顺序,形成一个图,规定较小的字母到较大的字母有一条「有向」的边。
建好图之后,使用拓扑排序,输出可能的字母先后顺序,并验证是否有环,如果有环返回空串,没有的话返回生成的字母顺序。
不过细节较多,见注释。
代码
class Solution {public String alienOrder(String[] words) {int n = words.length;int[] inDegree = new int[26];// 初始化为-1,表示该字符不存在Arrays.fill(inDegree, -1);// 出现过的字符种类int cnt = 0;for (String word : words) {for (char c : word.toCharArray()) {if (inDegree[c - 'a'] == -1) {cnt++;}inDegree[c - 'a'] = 0;}}// key为一个字符,val为比其小的所有字符// 这里使用set去重,不过好像用list也可以(如果发生了重复一定有环)Map<Character, Set<Character>> graph = new HashMap<>();// 比较相邻的两个单词,以生成字符先后顺序的图for (int i = 1; i < n; i++) {int p = 0;int q = 0;int len1 = words[i - 1].length();int len2 = words[i].length();// 找第一个不相同的字母while (p < len1 && q < len2 && words[i - 1].charAt(p) == words[i].charAt(q)) {p++;q++;}// 后面的字符串遍历完了,前面的字符串还剩余字母,例如abcd和abc,其实这种用例不符合条件不应该出现if (p < len1 && q == len2) {return "";} else if (p < len1 && q < len2) {// 都剩余字母没遍历完,当前p和q指向的字符就是不同的,例如abd和abc,那么就建立一条d到c的边,表示d比c小char c1 = words[i - 1].charAt(p);char c2 = words[i].charAt(q);boolean res = graph.computeIfAbsent(c1, k -> new HashSet<>()).add(c2);// 只有c1的set中第一次添加c2,才增加c2的入度if (res) {inDegree[c2 - 'a']++;}}}// 剩下就是拓扑排序基本写法,这里是BFSQueue<Character> q = new LinkedList<>();for (int i = 0; i < 26; i++) {if (inDegree[i] == 0) {q.offer((char) (i + 'a'));}}StringBuilder sb = new StringBuilder();while (!q.isEmpty()) {char cur = q.poll();sb.append(cur);Set<Character> l = graph.get(cur);// 注意cur可能不存在比其大的字母if (l == null) {continue;}for (char c : l) {inDegree[c - 'a']--;if (inDegree[c - 'a'] == 0) {q.offer(c);}}}// 如果sb长度小于字符种类,一定是有环return sb.length() == cnt ? sb.toString() : "";}}
