火星词典
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 28 ms, 内存: 16.0 MB
/*
思路:
1. 使用流处理构建图和入度数组。
2. 使用流进行拓扑排序。
*/
import java.util.*;
import java.util.stream.*;
public class AlienDictionaryStream {
public String alienOrder(String[] words) {
Map<Character, Set<Character>> graph = new HashMap<>();
Map<Character, Integer> inDegree = new HashMap<>();
Arrays.stream(words).forEach(word -> {
word.chars().forEach(c -> {
graph.putIfAbsent((char) c, new HashSet<>());
inDegree.putIfAbsent((char) c, 0);
});
});
IntStream.range(0, words.length - 1).forEach(i -> {
String word1 = words[i];
String word2 = words[i + 1];
if (word1.length() > word2.length() && word1.startsWith(word2)) {
return;
}
IntStream.range(0, Math.min(word1.length(), word2.length())).filter(j -> word1.charAt(j) != word2.charAt(j)).findFirst().ifPresent(j -> {
char parent = word1.charAt(j);
char child = word2.charAt(j);
if (graph.get(parent).add(child)) {
inDegree.put(child, inDegree.get(child) + 1);
}
});
});
Queue<Character> queue = inDegree.keySet().stream().filter(c -> inDegree.get(c) == 0).collect(Collectors.toCollection(LinkedList::new));
StringBuilder order = new StringBuilder();
while (!queue.isEmpty()) {
char current = queue.poll();
order.append(current);
graph.get(current).forEach(neighbor -> {
inDegree.put(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) == 0) {
queue.offer(neighbor);
}
});
}
return order.length() == inDegree.size() ? order.toString() : "";
}
}
解释
方法:
这道题解的思路基于图论中的拓扑排序。首先,题解尝试通过给定的单词列表构建一个有向图,其中节点代表字母,有向边代表字母间的顺序关系。使用边和入度数组来建立这个图的结构。接下来,题解遍历单词列表,比较相邻的单词,找到第一个不同的字母对,以此来确定字母间的顺序关系,即在图中添加边。特别的,如果发现短单词排在长单词后面,那么立即返回空字符串,因为这是不合法的。最后,题解使用拓扑排序算法来得到一个有效的字母顺序。如果排序过程中某个时刻没有入度为0的字母而图中仍有字母未处理,则说明存在环,也返回空字符串。
时间复杂度:
O(n + V + E)
空间复杂度:
O(26) 或 O(1)
代码细节讲解
🦆
在构建有向图时,如果两个单词相同,比如`aa`和`aa`,这种情况在代码中是如何处理的?是否会影响图的构建或是最终的结果?
▷🦆
题解中提到,如果较短的单词排在较长的单词之后,则返回空字符串。能否详细解释为什么这种情况下必然不存在合法的字母顺序?
▷🦆
在处理字母入度数组时,为什么只增加不同字母对中后一个字母的入度而不是两个字母都增加?这样的处理对拓扑排序的结果有何影响?
▷