现在你总共有 n 门课需要选,记为 0
到 n-1
。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]] 输出: true 解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]] 输出: false 解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
题目分析:非常好的一道题目,判断一个有向图中是否存在环。借助于BFS,记录下每个点的入度,首先将图中入度为0的点入队,然后在图上删去这个点,并且将与它们相连的点的入度减1,若某个点的入度减为0,则这个点要入队。重复以上步骤,最后图中若所有的点都删除了,则没有环;否则有环。
我们可以借助于map,将这个点指向的所有点,保存在一个vector中,将这个vector作为这个点(key)的value。
代码展示:
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
map<int,vector<int>> mp;
int inDegree[numCourses]; //表示每个点的入度
memset(inDegree,0,sizeof(inDegree));
bool isDeleteNode[numCourses]; //表示该点是否被删除
memset(isDeleteNode,0,sizeof(isDeleteNode));
for(auto pre:prerequisites){
if(mp.find(pre.first)!=mp.end()){
mp[pre.first].push_back(pre.second);
}
else{
vector<int> vec;
vec.push_back(pre.second);
mp[pre.first] = vec;
}
inDegree[pre.second] += 1;
}
queue<int> q;
for(int i=0;i<numCourses;i++){ //将所有入度为0的点入队
if(inDegree[i]==0)
q.push(i);
}
while(!q.empty()){
int temp = q.front();
isDeleteNode[temp] = true;
q.pop();
for(auto value:mp[temp]){
inDegree[value] -= 1;
if(inDegree[value]==0)
q.push(value);
}
}
for(int i=0;i<numCourses;i++){
if(!isDeleteNode[i])
return false;
}
return true;
}
};
补充:
本题若是用DFS来做的话,思路是这样的:用一个数组来标记访问过的结点,若在一次深度遍历中,某个结点的下一条边指向了一个已经访问过的结点,则表示有环。
若是判断一个无向图是否有环,步骤是:首先,求出图中所有点的度,将度小于等于1 的点删去,并且将与之相连的点的度减1,重复以上步骤,直到图中的点无法再改动。若还有没有删去的点,则表示有环,否则无环。