210. 课程表 II

2020-04-26  本文已影响0人  放下梧菲

现在你总共有 n 门课需要选,记为 0 到 n-1。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。

可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

示例 1:

输入: 2, [[1,0]]
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
示例 2:

输入: 4, [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。
说明:

输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
本题与https://www.jianshu.com/p/9cc632943de6
如出一辙,就是记录一下出节点的,顺序。因此我这里不再对DFS过多解释。

class Solution {
    vector<int> ans;
    int* visit;
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        
        visit=new int[numCourses];
        for(int i=0;i<numCourses;i++){
            visit[i]=0;//未访问过
        }
        vector<vector<int>> adj(numCourses);
        for(auto p : prerequisites){
            adj[p[1]].push_back(p[0]);            
        }
        for(int i=0;i<numCourses;i++){
            if( !dfs(adj,i)){
                delete []visit;
                vector<int> tmp;
                return tmp;
            }
        }
        reverse(ans.begin(),ans.end());
        return ans;
    }
    bool dfs( vector<vector<int>>& adj,int i){
        if(visit[i]==-1) return true;
        if(visit[i]==1) return false;

        visit[i]=1; //正在访问的状态

        for(auto v:adj[i]){
            if(!dfs(adj,v)) return false;
        }

        visit[i]=-1;//访问完毕,没有出现环
        ans.push_back(i);
        return true;
    }
};

在看了力扣题解后,还可以用BFS来做。其实BFS确实是更好理解。
输入: 4, [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
以这个为例子,我们先把入度为0的给取出来,这个肯定是最开始先决条件,如果一个都不存在那么就肯定是有环了。
在本题中是只有一个节点0,然后将0从图中删去,在观察剩下的节点里入度为0的节点。将其删去,直到没有节点为止。这样得到的删去的顺序就是结果了。而如果出现在一次循环中不存在入度为0的节点了,那么就说明里面有环。
下面的代码就是用的这个思路,在邻接表的基础上,用了一个数组记录入度数,也可以用哈希表。

class Solution {
    vector<int> ans;
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        
        vector<vector<int>> adj(numCourses);
        int degree[numCourses];
        for(int i=0;i<numCourses;i++) degree[i]=0;
        for(auto p : prerequisites){
            adj[p[1]].push_back(p[0]);
            degree[p[0]]++;            
        }
        queue<int> myQueue;
        for(int i=0;i<numCourses;i++){
            if(degree[i]==0) myQueue.push(i);
        }
        while(!myQueue.empty()){

            int k=myQueue.front();
            myQueue.pop();
            for(int i=0;i<adj[k].size();i++){
                degree[adj[k][i]]--;
                if(degree[adj[k][i]]==0){
                    myQueue.push(adj[k][i]);
                }
            }
            degree[k]=-1;//访问完毕该节点。
            ans.push_back(k);

        }
        
        if(ans.size()!=numCourses){
            vector<int> tmp;
            return tmp;
        }
        
        return ans;
    }
    
};
上一篇 下一篇

猜你喜欢

热点阅读