火星词典
难度:
标签:
题目描述
代码结果
运行时间: 26 ms, 内存: 16.1 MB
/*
题目思路:
1. 构建字符的入度表和邻接表。
2. 使用流式API对单词列表进行处理, 构建图并更新入度。
3. 使用流式API进行拓扑排序, 如果排序结果字符数与所有唯一字符数一致, 返回排序结果, 否则返回""。
*/
import java.util.*;
import java.util.stream.*;
public class AlienDictionaryStream {
public String alienOrder(String[] words) {
Map<Character, Long> inDegree = words.stream()
.flatMapToInt(String::chars)
.mapToObj(c -> (char) c)
.collect(Collectors.groupingBy(c -> c, Collectors.counting()));
Map<Character, List<Character>> adjList = words.stream()
.flatMapToInt(String::chars)
.mapToObj(c -> (char) c)
.distinct()
.collect(Collectors.toMap(c -> c, c -> new ArrayList<>()));
IntStream.range(0, words.length - 1).forEach(i -> {
String first = words[i];
String second = words[i + 1];
if (first.length() > second.length() && first.startsWith(second)) {
throw new IllegalArgumentException();
}
IntStream.range(0, Math.min(first.length(), second.length())).filter(j -> first.charAt(j) != second.charAt(j)).findFirst().ifPresent(j -> {
adjList.get(first.charAt(j)).add(second.charAt(j));
inDegree.put(second.charAt(j), inDegree.get(second.charAt(j)) + 1);
});
});
Queue<Character> queue = inDegree.entrySet().stream()
.filter(entry -> entry.getValue() == 0)
.map(Map.Entry::getKey)
.collect(Collectors.toCollection(LinkedList::new));
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
char current = queue.poll();
sb.append(current);
adjList.get(current).forEach(neighbor -> {
inDegree.put(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) == 0) {
queue.add(neighbor);
}
});
}
return sb.length() < inDegree.size() ? "" : sb.toString();
}
}
解释
方法:
该题解利用拓扑排序的方法来确定火星字典中字符的顺序。首先,建立一个字符间的依赖图,即从一个单词到下一个单词比较不同字符的位置,形成有向边。使用一个入度表来记录每个字符的入度。然后,使用一个队列实现广度优先搜索(BFS),将入度为0的字符依次加入队列。每次从队列中取出一个字符,表示这个字符在字典顺序中的下一个位置,然后减少其相邻节点的入度,并检查新的入度为0的节点加入队列。这个过程持续到队列为空。如果最终结果的长度等于字符集大小,表示找到了有效的顺序;如果不是,则可能存在环,表示没有有效的字符顺序。
时间复杂度:
O(n * L + V + E)
空间复杂度:
O(V + E)
代码细节讲解
🦆
在构建依赖图时,如何确保只添加有效的有向边,避免由于单词顺序错误造成的不必要的边?
▷🦆
代码中提到,如果一个单词是另一个单词的前缀,则可能直接返回空字符串。这种情况下,为什么不能简单地忽略这种前缀关系而继续构建剩余的依赖关系?
▷🦆
拓扑排序中,如果存在环怎样检测?题解中似乎没有明显的环检测步骤,请问这是如何实现的?
▷🦆
当队列中的字符被全部处理后,结果字符串的长度与字符集大小相等才认为排序成功。在哪些情况下,这两者的长度会不相等?
▷相关问题
课程表 II
现在你总共有 numCourses
门课需要选,记为 0
到 numCourses - 1
。给你一个数组 prerequisites
,其中 prerequisites[i] = [ai, bi]
,表示在选修课程 ai
前 必须 先选修 bi
。
- 例如,想要学习课程
0
,你需要先完成课程1
,我们用一个匹配来表示:[0,1]
。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:[0,1]
解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
示例 2:
输入:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] 输出:[0,2,1,3] 解释:总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。 因此,一个正确的课程顺序是[0,1,2,3]
。另一个正确的排序是[0,2,1,3]
。
示例 3:
输入:numCourses = 1, prerequisites = [] 输出:[0]
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= numCourses * (numCourses - 1)
prerequisites[i].length == 2
0 <= ai, bi < numCourses
ai != bi
- 所有
[ai, bi]
互不相同