210. 课程表 II

Q:

现在你总共有 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] 。

A:

DFS,这个要用逆邻接表,对当前节点要找它的所有前驱。
py:

class Solution:
    def findOrder(self, numCourses: int, prerequisites):
        temp=[[] for i in range(numCourses)]
        visited=[0 for i in range(numCourses)]
        res=[]
        for x,y in prerequisites:
            temp[x].append(y)   #逆邻接表
        def dfs(i):
            if visited[i]==1:
                return False
            if visited[i]==-1:
                return True
            visited[i]=1
            for pre_i in temp[i]:
                if not dfs(pre_i):
                    return False
            res.append(i)
            visited[i]=-1
            return True
        for i in range(numCourses):
            if not dfs(i):
                return []
        return res

cpp:

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) 
    {
        // if(prerequisites.size()==0 or prerequisites[0].size()==0)
        // {
        //     return vector<int>();
        // }
        vector<vector<int>> reverse_matrix(numCourses,vector<int>());   //逆邻接矩阵
        for(auto vec:prerequisites)
        {
            reverse_matrix[vec[0]].push_back(vec[1]);   //matrix[i]包含的是i的前驱课程
        }
        vector<int> res,visited(numCourses,0);
        for(int i=0;i<numCourses;++i)
        {
            if(not dfs(i,reverse_matrix,res,visited))
            {
                return vector<int>();   //只要有任何一次dfs返回false,就说明有环直接退出
            }
        }
        return res;
    }
    bool dfs(int cur,vector<vector<int>>&matrix,vector<int>&res,vector<int>&visited)
    {
        if(visited[cur]==-1)    //其他dfs中遍历到了,直接退出
        {
            return true;
        }
        if(visited[cur]==1) //本轮dfs中遍历到的节点又遍历到了,说明有环,无解
        {
            return false;
        }
        visited[cur]=1; //本次dfs递归中设为1,最后设为-1
        for(auto pre_cur:matrix[cur])   //pre_cur为cur的前驱课程
        {
            if(not dfs(pre_cur,matrix,res,visited))
            {
                return false;   //这里是最关键一步,dfs(cur)中先运行dfs(pre_cur),找所有前驱
            }
        }
        //若上面for循环没返回false,说明已经将所有cur的前驱都加入了序列
        res.push_back(cur); //这时候再加入cur,这样就满足了pre_cur(先修课程)先加入序列,(后继课程)cur后加入
        visited[cur]=-1;    //因为当前dfs要结束了,把cur的标志置-1,
        //这样在之后另外的dfs中若遍历到当前cur节点,说明有环,作为查错使用
        return true;
    }
};

BFS,这个比较好想,就正常拓扑遍历过程中保存下每次的节点

class Solution:
    def findOrder(self, numCourses: int, prerequisites):
        from collections import deque
        temp=[[] for i in range(numCourses)]
        indegree=[0 for i in range(numCourses)]
        for x,y in prerequisites:
            temp[y].append(x)
            indegree[x]+=1
        queue=deque()
        for i in range(numCourses):
            if indegree[i]==0:
                queue.append(i)
        res=[]
        while queue:
            numCourses-=1
            cur=queue.popleft()
            res.append(cur)
            for x in temp[cur]:
                indegree[x]-=1
                if indegree[x]==0:
                    queue.append(x)
        return res if not numCourses else []
posted @ 2019-08-18 19:29  NeoZy  阅读(108)  评论(0编辑  收藏  举报