题目的意思大概是这样:给你一个整数数组
org
,它是一个从 1 到
n
的排列,同时还给了一些子序列组成的列表
seqs
。你需要通过这些子序列判断,能不能唯一地重建出原始序列
org
。
举个例子,假设
org = [1, 2, 3]
,而
seqs = [[1, 2], [1, 3]]
,从这些子序列中你就没办法唯一确定原始序列,因为
[1, 2, 3]
和
[1, 3, 2]
都是可能的。但如果
seqs = [[1, 2], [2, 3]]
,那么就可以唯一确定原始序列
org = [1, 2, 3]
。
这背后的逻辑是什么呢?我们需要通过
seqs
提供的前后顺序关系,构建一个有向图,然后利用拓扑排序来判断能不能唯一地构造出
org
。唯一性怎么判断呢?简单说就是每次在排序过程中,只有一个节点可以被确定为下一个节点,否则就说明顺序不是唯一的。
为了更好地理解,我直接用代码带你走一遍流程吧。下面是用 Java 实现的解决方案:
import java.util.*;
public class SequenceReconstruction {
public boolean sequenceReconstruction(int[] org, List> seqs)
{
// 边界情况判断
if (org == null || org.length == 0 || seqs == null || seqs.isEmpty()) {
return false;
}
// 构建图和入度表
Map> graph = new HashMap<>();
Map inDegree = new HashMap<>();
for (List seq : seqs) {
for (int num : seq) {
graph.putIfAbsent(num, new HashSet<>());
inDegree.putIfAbsent(num, 0);
}
}
// 如果 seqs 中包含的数字和 org 的数字集合不一致,直接返回 false
if (graph.size() != org.length) {
return false;
}
// 构建图和计算入度
for (List seq : seqs) {
for (int i = 1; i int prev = seq.get(i - 1);
int next = seq.get(i);
if (graph.get(prev).add(next)) { // 避免重复边
inDegree.put(next, inDegree.get(next) + 1);
}
}
}
// 拓扑排序
Queue queue = new LinkedList<>();
for (Map.Entry entry : inDegree.entrySet()) {
if (entry.getValue() == 0) {
queue.offer(entry.getKey());
}
}
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 neighbor : graph.get(curr)) {
inDegree.put(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) == 0) {
queue.offer(neighbor);
}
}
}
return index == org.length; // 判断是否遍历完整个 org
}
public static void main(String[] args) {
SequenceReconstruction solution = new SequenceReconstruction();
int[] org = {1, 2, 3};
List> seqs = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(1, 3),
Arrays.asList(2, 3)
);
System.out.println(solution.sequenceReconstruction(org, seqs)); // true
}
}
来,我们逐步拆解这段代码的核心逻辑:
-
构建图和入度表
:使用邻接表的形式存储图,同时记录每个节点的入度。入度是啥呢?简单说就是有多少箭头指向这个节点。
-
检查一致性
:通过
seqs
构建图的时候,顺便判断
seqs
是否包含了所有的
org
中的元素。如果不一致,那不用想了,直接返回
false
。
-
拓扑排序
:从入度为 0 的节点开始,每次只能选择一个节点,否则就不唯一。同时检查排序的过程中,生成的顺序是否和
org
一致。
-
最后校验
:遍历完所有节点后,看看是不是刚好完整覆盖了
org
。
怎么样,是不是清晰了一些?这个题目其实是拓扑排序在实际问题中的一个很有代表性的应用。解决这类题目最重要的就是把抽象问题转化成图的模型,然后一步步捋清楚逻辑。
最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:
https://www.songshuhezi.com/deepseek