思路
BFS或者DFS判断图中是否有环。
BFS:每次选取图中入度为0的node,然后删除该node,并将该node至其后继node的变删除,更新后继node的入度。若无法找到入度为0的node,则出现环。
DFS:在搜索过程中,使用todo数组和done数组标记各node。todo数组表示正在检查当前node的各出边,done数组表示当前node已访问过。如果在遍历过程中,遇到在todo数组内的node,表示当前搜索路径已经经过了该node,但是路径又返回至该node,说明遇到环。如果在遍历过程中,遇到不在todo,但是在done内的node,说明此node的各出边已检查完,通过该节点的出边无法形成环,那么再此访问该node的时候,也无法形成环,所以直接停止搜索,提高效率。
代码
未经优化
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
if (prerequisites.empty()) return true;
unordered_map<int, int> degreeGraph;
for (int i = 0; i < numCourses; ++i)
degreeGraph[i] = 0;
for (int i = 0; i < prerequisites.size(); ++i) {
degreeGraph[prerequisites[i][0]]++;
}
for (int i = 0; i < numCourses; ++i) {
bool findZeroDegreeNode = false;
int zeroDegreeNode = -1;
for (int j = 0; j < numCourses; ++j) {
if (!degreeGraph[j]) {
findZeroDegreeNode = true;
zeroDegreeNode = j;
degreeGraph[j] = -1;
break;
}
}
if (!findZeroDegreeNode) return false;
for (int j = 0; j < prerequisites.size(); ++j) {
if (prerequisites[j][1] == zeroDegreeNode)
degreeGraph[prerequisites[j][0]]--;
}
}
return true;
}
};
BFS
解法1
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
graph g = buildGraph(numCourses, prerequisites);
vector<int> degrees = computeIndegrees(g);
for (int i = 0; i < numCourses; i++) {
int j = 0;
for (; j < numCourses; j++) {
if (!degrees[j]) {
break;
}
}
if (j == numCourses) {
return false;
}
degrees[j]--;
for (int v : g[j]) {
degrees[v]--;
}
}
return true;
}
private:
typedef vector<vector<int>> graph;
graph buildGraph(int numCourses, vector<pair<int, int>>& prerequisites) {
graph g(numCourses);
for (auto p : prerequisites) {
g[p.second].push_back(p.first);
}
return g;
}
vector<int> computeIndegrees(graph& g) {
vector<int> degrees(g.size(), 0);
for (auto adj : g) {
for (int v : adj) {
degrees[v]++;
}
}
return degrees;
}
};
解法2
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph(numCourses, vector<int>());
vector<int> degree(numCourses, 0);
for ( const auto &pair : prerequisites) {
graph[pair[1]].push_back(pair[0]);
++degree[pair[0]];
}
queue<int> qu;
for (int i = 0; i < numCourses; ++i)
if (!degree[i]) qu.push(i);
while (!qu.empty()) {
int cur = qu.front();
qu.pop();
--numCourses;
for (int i = 0; i < graph[cur].size(); ++i) {
if (--degree[graph[cur][i]] == 0) qu.push(graph[cur][i]);
}
}
return numCourses == 0;
}
};
DFS
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph = buildGraph(numCourses, prerequisites);
// vector<int> degree = computeDegree(numCourses, prerequisites);
vector<bool> todo(numCourses, false), done(numCourses, false);
for (int i = 0; i < numCourses; ++i) {
if (!done[i] && !acyclic(graph, todo, done, i))
return false;
}
return true;
}
private:
vector<vector<int>> buildGraph(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph(numCourses, vector<int>());
for (const auto &pair : prerequisites) {
graph[pair[1]].push_back(pair[0]);
}
return graph;
}
vector<int> computeDegree(int numCourses, vector<vector<int>> &prerequisites) {
vector<int> degree(numCourses, 0);
for (const auto &pair : prerequisites) {
++degree[pair[0]];
}
return degree;
}
bool acyclic(vector<vector<int>> &graph, vector<bool> &todo, vector<bool> &done, int i) {
if (todo[i]) return false;
if (done[i]) return true;
todo[i] = true;
done[i] = true;
for (const auto &v : graph[i]) {
if (!acyclic(graph, todo, done, v))
return false;
}
todo[i] = false;
return true;
}
};