boolean[] mark;//之前已经遍历的节点
boolean[] on;//本此路径上的节点
boolean flag;//是否有环
String ans;//结果,模拟栈
Deque<Integer>[] adj;//邻接表
//添加v到w的边
public void addEdge(int v,int w){
if(adj[v]==null) adj[v]=new ArrayDeque<>();
if(adj[w]==null) adj[w]=new ArrayDeque<>();
if(!adj[v].contains(w))
adj[v].offer(w);
//当w包含v时形成闭环
if(adj[w].contains(v))
flag=true;
}
public String alienOrder(String[] words) {
int n=words.length;
if(n==1) return words[0];
mark=new boolean[26];
on=new boolean[26];
flag=false;
ans=new String();
adj=new ArrayDeque[26];
Set<Character> set=new HashSet<>();//存储出现的字母
//取相邻的两个单词
for(int i=1;i<n;i++){
//判断前面单词是否包含后面单词
if(words[i-1].indexOf(words[i])==0&&
words[i-1].length()>words[i].length())
return "";
char[] chs1=words[i-1].toCharArray();
char[] chs2=words[i].toCharArray();
boolean find=false;//是否找到能确定顺序的两个字母
for(int j=0,k=0;j<chs1.length||k<chs2.length;j++,k++){
if(j<chs1.length)
set.add(chs1[j]);
if(k<chs2.length)
set.add(chs2[k]);
if(!find){
if(j<chs1.length&&k<chs2.length&&chs1[j]!=chs2[k]){
find=true;
addEdge(chs1[j]-'a',chs2[k]-'a');
}
}
}
}
//从每个顶点开始,如果已经搜索则跳过
for (char ch:set) {
if(flag)
return "";
if (!mark[ch-'a']) {
dfs(adj,ch-'a');
}
}
return ans;
}
public void dfs(Deque<Integer>[] adj,int v){
mark[v]=true;
on[v]=true;
if(adj[v]!=null){
for (int w : adj[v]) {
if(!mark[w]){
dfs(adj,w);
} else if(on[w]){//已经标记的点,可能是之前遍历过的,也可能是本次路径上的
flag=true;
return;
}
}
}
on[v]=false;//回溯还原路径上点的状态
ans=(char)(v+'a')+ans;//当该点没有指向,或已经遍历完后面的点,该点入栈
}
07-05
222
05-13
1202