现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。
给定一个字符串列表 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] 仅由小写英文字母组成
这道题可能刚看还理解不了意思,我们用示例1 words = ["wrt","wrf","er","ett","rftt"]
来走一遍。
- 首先,
wrt
与wrf
,前两个字符wr
相同,而第三个字符"t
与f
不同,且wrt
在wrf
前面,因此t
的顺序在f
前面。 - 接下来,
wrf
与er
,第一个字符w
与e
不同,且wrf
在er
前面,因此w
的顺序在e
前面。 - 然后,
er
与ett
,第一个字符e
相同,而第二个字符r
与t
不相同,因此r
的顺序在t
之前。 - 最后,
"et"
与rftt
,第一个字符e
与r
不同,因此e
的顺序在r
前面。
我们可以综合一下之前的结论,t
->f
,w
->e
,r
->t
,e
->r
,因此最终可以得出有且仅有一种顺序,即"wertf"
。
代码实现如下:
class Solution {
public String alienOrder(String[] words) {
boolean[] exist=new boolean[26];
int[] in=new int[26];
Set<Integer>[] edge=new HashSet[26];
int count=0;
for (int i=0;i<26;i++){
edge[i]=new HashSet<Integer>();
}
for (int j=0;j<words.length;j++){
String str=words[j];
for (int k=0;k<str.length();k++){
if (!exist[str.charAt(k)-'a']){
count++;
exist[str.charAt(k)-'a']=true;
}
}
}
for (int m=1;m< words.length;m++){
String pre=words[m-1];
String nex=words[m];
int index=0;
while (index<pre.length()&&index<nex.length()){
if (pre.charAt(index)==nex.charAt(index))index++;
else break;
}
if (index<pre.length()&&index<nex.length()){
if (!edge[pre.charAt(index)-'a'].contains(nex.charAt(index)-'a')){
in[nex.charAt(index)-'a']++;
edge[pre.charAt(index)-'a'].add(nex.charAt(index)-'a');
}
}
if (index<pre.length()&&index>=nex.length())return "";//特殊判断
}
Queue<Integer> queue=new LinkedList<>();
StringBuilder sb=new StringBuilder();
for (int i=0;i<26;i++){
if (in[i]==0&&exist[i])queue.offer(i);
}
while (!queue.isEmpty()){
int po=queue.poll();
sb.append((char)(po+'a'));
for (Integer ind:edge[po]){
in[ind]--;
if (in[ind]==0){
queue.add(ind);
}
}
}
return sb.length()==count?sb.toString():"";
}
}
需要注意的是,测试用例有一个特殊的例子:["abc","ab"]
,这个示例不符合
如果前面
min(s.length, t.length)
字母都相同,那么s.length < t.length
时,s
的字典顺序也小于t
的要求,因此需要特别的判断条件。