题目LCR 115. 序列重建
给定一个整数数组 nums
,其中 nums
是一个长度为 n
的排列,还提供了一个二维数组 sequences
,每个 sequences[i]
都是 nums
的子序列。要求判断 nums
是否是唯一的最短超序列。
最短超序列是一个长度最短且包含所有 sequences[i]
子序列的序列。要判断 nums
是否为唯一的最短超序列,必须确保没有其他序列能与 nums
不同但依然满足所有 sequences[i]
子序列的要求。
解题思路
核心思路:由于题目涉及元素之间的相对顺序关系,这些顺序关系可以通过有向图来表示。只要通过拓扑排序确定有向图的排序是唯一的,并且所有关系都是单向确定的,那么超序列的可能性也是唯一的。
这道题的核心在于检查 nums
是否是给定的 sequences
的唯一最短超序列。我们可以通过 拓扑排序 来验证唯一性,具体步骤如下:
- 构建有向图:从
sequences
中提取元素间的顺序关系,建立有向图,节点是nums
的元素,边表示元素之间的相对顺序。 - 记录入度:统计每个节点的入度(即指向该节点的边的数量)。
- 拓扑排序:
- 从入度为 0 的节点开始逐步进行排序。
- 若每次只能有一个入度为 0 的节点加入排序队列,说明序列是唯一确定的;如果某时刻有多个入度为 0 的节点,说明可能存在多个有效的序列,返回
false
。
- 验证排序结果:若拓扑排序得到的序列与
nums
一致,则说明nums
是唯一的最短超序列,返回true
;否则返回false
。
代码实现
class Solution {
public:
bool sequenceReconstruction(vector<int>& nums, vector<vector<int>>& sequences) {
int n = nums.size();
// 构建图和入度表
vector<vector<int>> graph(n + 1); // n+1 因为节点从 1 开始
vector<int> inDegree(n + 1, 0);
// 构建图
for (const auto& seq : sequences) {
for (int i = 1; i < seq.size(); ++i) {
int prev = seq[i - 1], next = seq[i];
graph[prev].push_back(next);
inDegree[next]++;
}
}
// 拓扑排序
queue<int> q;
// 首先将入度为 0 的节点加入队列
for (int i = 1; i <= n; ++i) {
if (inDegree[i] == 0) {
q.push(i);
}
}
vector<int> topoResult;
while (!q.empty()) {
// 如果队列中有多个元素,说明拓扑排序不是唯一的
if (q.size() > 1) {
return false;
}
int node = q.front();
q.pop();
topoResult.push_back(node);
// 遍历该节点的所有邻居,减少其入度
for (int neighbor : graph[node]) {
inDegree[neighbor]--;
// 如果某个邻居的入度为 0,加入队列
if (inDegree[neighbor] == 0) {
q.push(neighbor);
}
}
}
// 判断拓扑排序的结果是否与 nums 一致
return topoResult == nums;
}
};