1 题目
拓扑排序参考:图-有向图-无向图-二分图-拓扑排序_hclbeloved的博客-CSDN博客
2 代码实现
//拓扑排序
class Solution {
public:
bool sequenceReconstruction(vector<int>& org, vector<vector<int>>& seqs) {
if (seqs.empty())
return false;
unordered_map<int, unordered_set<int>> graph;
int n = org.size();
//buildGraph返回有效约束的数量
int nonZeroNeighbour = buildGraph(n, seqs, graph);
//1到n的排列的唯一创建,需要后面共有n-1个有效约束才行,如果小于n-1个有效约束肯定无法唯一确定
if (nonZeroNeighbour < n-1)
return false;
vector<bool> visited(n+1, false), onPath(n+1, false);
bool hasCycle = false;
vector<int> topology;
// 因为图不一定是联通的,可能存在多个子图
// 所以要把每个节点都作为起点进行一次遍历
for (int i=1;i<=n;++i)
{
if (!graph.count(i))
return false;
if (!visited[i])
{
dfs(graph, i, visited, onPath, hasCycle, topology);
if (hasCycle)
return false;
}
}
//逆序输出便是拓扑排序
vector<int> org2(topology.rbegin(), topology.rend());
return org2 == org;
}
int buildGraph(int n, vector<vector<int>>& seqs, unordered_map<int, unordered_set<int>>& graph)
{
int nonZeroNeighbour = 0;
for (auto& v : seqs)
{
int size = v.size();
for (int i=0;i<size;++i)
{
if (i+1 < size)
{
//由于下面graph[v[i]的调用可能导致nonZeroNeighbour计算不正确,所以使用了 graph[v[i]].empty() 判断
if (!graph.count(v[i]) || graph[v[i]].empty())
{
++nonZeroNeighbour;
}
graph[v[i]].insert(v[i+1]);
}
else
{
/* 测试用例
[5,3,2,4,1]
[[5,3,2,4],[4,1],[1],[3],[2,4],[1000000000]]
*/
if (v[i] > n || v[i] <= 0)
return -1;
graph[v[i]];
}
}
}
return nonZeroNeighbour;
}
void dfs(unordered_map<int, unordered_set<int>>& graph, int index, vector<bool>& visited, vector<bool>& onPath, bool& hasCycle, vector<int>& topology)
{
if (onPath[index])
{
hasCycle = true;
return;
}
if (visited[index])
return;
visited[index] = true;
// 开始遍历节点 index
onPath[index] = true;
for (int i : graph[index])
{
dfs(graph, i, visited, onPath, hasCycle, topology);
}
topology.push_back(index);
// 节点 index 遍历完成
onPath[index] = false;
}
};