能进行拓补排序的图必须是有向无环图,直接用DFS判断图里面是否存在环,即不能存在回边,用两个时钟数组记录每个节点的进入时钟pre和返回时钟post,回边有这样的特性,如果一条边(u,v)是一条回边,那么pre(u)>pre(v),post(u)<post(v)。
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
unordered_map<int, vector<int>> adjTable;
for (int i = 0; i < prerequisites.size(); i++) {
adjTable[prerequisites[i].first].push_back(prerequisites[i].second);
}
const int arraySize = numCourses;
bool visited[arraySize];
int preClock[arraySize];
int postClock[arraySize];
int globalClock = 0;
for (int i = 0; i < arraySize; i++) {
visited[i] = false;
preClock[i] = -1;
postClock[i] = -1;
}
stack<int> DFSStack;
for (int i = 0; i < numCourses; i++) {
if (!visited[i]) {
DFSStack.push(i);
while (!DFSStack.empty()) {
int currentNode = DFSStack.top();
preClock[currentNode] = globalClock;
globalClock++;
visited[currentNode] = true;
int count = 0;
for (int j = 0; j < adjTable[currentNode].size(); j++) {
if (!visited[adjTable[currentNode][j]]) {
DFSStack.push(adjTable[currentNode][j]);
count++;
} else if (preClock[currentNode] > preClock[adjTable[currentNode][j]] && postClock[adjTable[currentNode][j]] == -1) {//判断回边的条件
return false;
}
}
if (count == 0) {
DFSStack.pop();
postClock[currentNode] = globalClock;
globalClock++;
}
}
}
}
return true;
}
};
第二题仍然按照这个思路,不过这里要返回排序结果,按照一种拓补排序的算法,给每个节点记录preClock和postClock,按照postClock的递减顺序排序的话就是一种合法的拓补排序结果,而且深搜的时候,当且仅当节点被pop出栈的时候才会计算它的postClock,所以也不需要显式计算postClock,只需要每次pop节点的时候将这个节点插到结果向量的开头就可以了。
算法描述:
TOPOLOGICAL-SORT(G)
1 call DFS(G) to compute finishing times post[v] for each vertex v
2 as each vertex is finished, insert it onto the front of a linked list
3 return the linked list of vertices
算法复杂度:O(V+E)
代码:
class Solution {
public:
vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
unordered_map<int, vector<int>> adjTable;
for (int i = 0; i < prerequisites.size(); i++) {
adjTable[prerequisites[i].second].push_back(prerequisites[i].first);
}
int globalClock = 0;
const int vecSize = numCourses;
vector<int> resultVec;
stack<int> nodeStack;
int preClock[vecSize], postClock[vecSize];
bool visited[vecSize];
for (int i = 0; i < vecSize; i++) {
preClock[i] = -1;
postClock[i] = -1;
visited[i] = false;
}
for (int startNode = 0; startNode < numCourses; startNode++) {
if (visited[startNode]) {
continue;
}
nodeStack.push(startNode);
visited[startNode] = true;
preClock[0] = globalClock;
globalClock++;
while (!nodeStack.empty()) {
int curNode = nodeStack.top();
bool pushFlag = false;
for (int i = 0; i < adjTable[curNode].size(); i++) {
if (!visited[adjTable[curNode][i]]) {
nodeStack.push(adjTable[curNode][i]);
visited[adjTable[curNode][i]] = true;
preClock[adjTable[curNode][i]] = globalClock;
globalClock++;
pushFlag = true;
break;
} else if (preClock[adjTable[curNode][i]] < preClock[curNode] && postClock[adjTable[curNode][i]] == -1) {
return {};
}
}
if (!pushFlag) {
nodeStack.pop();
postClock[curNode] = globalClock;
globalClock++;
resultVec.insert(resultVec.begin(), curNode);
}
}
}
return resultVec;
}
};