class Solution {
public String alienOrder(String[] words) {
//这一题给我们的信息是外星文的一系列单词,要求我们找出一个符合条件的外星文字典序列,我们可以运用图的拓扑排序算法找到这样一个序列,想要运用图的相关算法,必须先找出图的节点和边,我们把每个字母当做是图的节点,对于每个字母的先后顺序当做是图的一条边,
//创建图和图的入度
Map<Character,Set<Character>> graph = new HashMap<>();
Map<Character,Integer> inDegrees = new HashMap<>();
for(String word : words){
//取出每个字符来,创建图的节点和inDegrees的节点
char[] chars = word.toCharArray();
for(char c : chars){
graph.putIfAbsent(c,new HashSet<Character>());
inDegrees.putIfAbsent(c,0);
}
}
//运用words来寻找图中的先后顺序关系,我们可以对比相邻的两个单词找到第一个不同的字符这样就表示前一个的第一个不同的字符就小于后一个不同的字符
for(int i = 1;i < words.length;i++){
String w1 = words[i - 1];
String w2 = words[i];
//首先判断两个字符创是不是非法字符创,也就是说后一个字符串是前一个字符串的前缀这是决不允许的
if(w1.startsWith(w2) && !w1.equals(w2)){
return "";
}
//接着就要找到两个字符串的第一个不同位置进行判断
for(int j = 0;j < w1.length() && j < w2.length();j++){
char c1 = w1.charAt(j);
char c2 = w2.charAt(j);
if(c1 != c2){
if(!graph.get(c1).contains(c2)){
graph.get(c1).add(c2);
inDegrees.put(c2,inDegrees.getOrDefault(c2,0) + 1);
}
break;
}
}
}
//构建完成图和入度之后我们正式开始拓扑排序算法
Queue<Character> queue = new LinkedList<>();
StringBuilder result = new StringBuilder();
//首先找出图中所有入度为0的节点将其作为起始节点开始
for(char c : inDegrees.keySet()){
if(inDegrees.get(c) == 0){
queue.offer(c);
}
}
while(!queue.isEmpty()){
//对于每一个节点来说先出队
char c = queue.poll();
//加入结果集合
result.append(c);
//在图中删除该节点,也就是说,遍历在它后面的节点将他们的入度减1,如果此时入度为0直接入队
for(char ch : graph.get(c)){
inDegrees.put(ch,inDegrees.get(ch) - 1);
if(inDegrees.get(ch) == 0){
queue.offer(ch);
}
}
}
//遍历结束之后要看拓扑排序序列是否包含所有的图节点
return result.length() == graph.size() ? result.toString() : "";
}
}