序列重建
难度:
标签:
题目描述
代码结果
运行时间: 82 ms, 内存: 19.6 MB
/*
* Problem: Sequence Reconstruction
* Given an original sequence org and a list of sequences seqs, write a method to determine if org can be uniquely reconstructed from the sequences in seqs. The original sequence org is a permutation of the integers from 1 to n, with 1 ≤ n ≤ 10^4. Reconstruction means building the shortest common supersequence of the sequences in seqs (i.e., a sequence that has all sequences in seqs as subsequences) and it should be unique.
*
* Approach:
* 1. Use a graph to represent dependencies between elements.
* 2. Use a topological sort to determine if there's a unique way to reconstruct the sequence.
*/
import java.util.*;
import java.util.stream.*;
public class SequenceReconstruction {
public boolean sequenceReconstruction(int[] org, List<List<Integer>> seqs) {
if (org.length == 0 || seqs.size() == 0) return false;
Map<Integer, Set<Integer>> graph = Arrays.stream(org).boxed().collect(Collectors.toMap(k -> k, v -> new HashSet<>()));
Map<Integer, Integer> inDegree = Arrays.stream(org).boxed().collect(Collectors.toMap(k -> k, v -> 0));
int count = seqs.stream().mapToInt(List::size).sum();
if (count < org.length) return false;
for (List<Integer> seq : seqs) {
for (int i = 0; i < seq.size(); i++) {
if (!graph.containsKey(seq.get(i))) return false;
if (i > 0) {
int prev = seq.get(i - 1);
int curr = seq.get(i);
if (graph.get(prev).add(curr)) {
inDegree.put(curr, inDegree.get(curr) + 1);
}
}
}
}
Queue<Integer> queue = inDegree.entrySet().stream()
.filter(entry -> entry.getValue() == 0)
.map(Map.Entry::getKey)
.collect(Collectors.toCollection(LinkedList::new));
int index = 0;
while (!queue.isEmpty()) {
if (queue.size() > 1) return false;
int curr = queue.poll();
if (org[index] != curr) return false;
index++;
for (int next : graph.get(curr)) {
inDegree.put(next, inDegree.get(next) - 1);
if (inDegree.get(next) == 0) {
queue.add(next);
}
}
}
return index == org.length;
}
}
解释
方法:
这个题解使用了拓扑排序的思路。首先根据给定的序列构建有向图,然后对图进行拓扑排序,判断拓扑排序的结果是否与给定的 nums 数组相同。在构建有向图时,使用 nexts 数组记录每个节点的后继节点,使用 inDegrees 数组记录每个节点的入度。在拓扑排序时,使用队列 q 存储入度为 0 的节点,每次从队列中取出一个节点,将其与 nums 数组中的元素进行比较,然后将其所有后继节点的入度减 1,如果入度变为 0,则将后继节点加入队列。如果在排序过程中出现了与 nums 数组不一致的情况,或者在某一轮中入度变为 0 的节点数量大于 1,则说明给定的序列无法唯一确定一个超序列,返回 False。最后,如果拓扑排序成功完成,且 nums 数组中的所有元素都被访问到,则说明可以重建出唯一的超序列,返回 True。
时间复杂度:
O(n+m)
空间复杂度:
O(n)
代码细节讲解
🦆
在构建有向图时,为何需要使用两个数组nexts和inDegrees分别记录后继节点和节点入度?它们在算法中分别承担什么角色?
▷🦆
题解中提到,如果初始时入度为0的节点数量大于1,则无法唯一确定超序列。为什么多个入度为0的节点会导致无法唯一确定超序列?
▷🦆
当拓扑排序中的当前节点与nums数组中的元素不一致时,为何直接判断无法重建超序列?是否存在其他可能的情况允许继续拓扑排序?
▷🦆
在处理拓扑排序的过程中,如果在某一轮中入度变为0的节点数量大于1,题解选择返回False。这种情况下,是否还有其他策略可以继续尝试重建超序列?
▷相关问题
课程表 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]
互不相同