题目
思路
拓扑排序问题
给定一个包含 nn 个节点的有向图 GG,我们给出它的节点编号的一种排列,如果满足:
对于图 GG 中的任意一条有向边 (u, v)(u,v),u 在排列中都出现在 v 的前面。
此问题可转换为:求解该图的拓扑排序。
DFS
设置visited数组,0代表未访问过,1代表正在访问但是还未回溯到该点,-1代表访问结束。遍历所有点,如果未访问过,则以该点进行DFS。如果此点已经访问结束,直接返回;如果此点正在访问还未回溯,设置失败跳出;如果此点未访问过,设置状态为正在访问还未回溯,遍历其连接的节点,分别对每个点进行DFS,遍历结束后设置该点状态为访问结束状态并且将该点送入结果数组。如果没有失败跳出,最后结束后反转结果数组即为拓扑排序结果。
BFS
设置结点入度统计数组,首先统计各个结点的入度,将入度为0的结点送入队列初始化队列。然后循环判断队列是否为空,非空时取出队首元素,将队首元素添加到结果数组,并将队首元素连接的节点的入度-1,将此时入度为0的结点送入队列,循环直到队列为空。如果结果数组的长度与节点数相等,则找到排序结果,若不等于节点数,则不存在拓扑排序结果。
实现
DFS
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
cool = false;
for (vector<int> index : prerequisites)
edges[index[1]].emplace_back(index[0]);
for (int i = 0; i < numCourses && !cool; ++i)
if (!visited[i])
dfs(i);
if (cool)
return false;
reverse(result.begin(), result.end());
return true;
}
void dfs(int node) {
if (visited[node] == -1 || cool)
return;
if (visited[node] == 1) {
cool = true;
return;
}
visited[node] = 1;
for (int index : edges[node])
dfs(index);
visited[node] = -1;
result.emplace_back(node);
}
private:
vector<vector<int>> edges;
vector<int> result;
vector<int> visited;
bool cool;
BFS
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> edges(numCourses);
vector<int> into_nums(numCourses);
vector<int> ret;
queue<int> queue;
for (vector<int> index : prerequisites) {
edges[index[1]].emplace_back(index[0]);
into_nums[index[0]]++;
}
for (int i = 0; i < numCourses; ++i)
if (into_nums[i] == 0)
queue.emplace(i);
while (!queue.empty()) {
int temp = queue.front();
queue.pop();
ret.emplace_back(temp);
for (int index : edges[temp])
if (--into_nums[index] == 0)
queue.emplace(index);
}
if (ret.size() != numCourses)
return {};
else
return ret;
}
};