Leetcode:210. Course Schedule II

Description

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

For example:

2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]

4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].

Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
You may assume that there are no duplicate edges in the input prerequisites.

解题思路

本题意共有n节课程,课程编号从0至n-1。一些课程可能有先修要求,比如修0号课程前需要先修1号课程,表示为[0,1]。题目给出课程数和先后修课程对,要求返回完成所有课程的顺序。可能有很多正确的上课顺序,你只需返回其中一种。如果不可能完成,则返回空数组。
此题是Course Schedule的进阶版,前者只需得出能否完成所有课程即可,本题还需要给出上课顺序。实际上这是一个求拓扑排序的题。可以有2种求解方法,采用DFS/BFS算法解题。

•采用bfs。前处理时得到每个节点的入度。每次将入度为0的节点入队。出队时将出队节点的邻接节点的入度减1,并将出队节点编号计入res数组中。循环该过程直到队列为空。如仍有节点未被访问,则说明课程关系图中出现了环,不可能完成所有课程。否则,res中的编号顺序就是上课顺序。

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<unordered_set<int>> graph(numCourses);
        for (auto i : prerequisites) {
            graph[i.second].insert(i.first);//因使用链表,不能用push_back
        }
        vector<int> degree(graph.size(),0);
        for (auto i : graph) {
            for (auto j : i) {
                degree[j]++;
            }
        }

        queue<int> q;
        vector<int> res;
        for (int i = 0; i < numCourses; i++) {
            if (!degree[i]) q.push(i);
        }
        for (int i = 0; i< numCourses; i++) {
            if (q.empty()) return {};
            int t = q.front();
            q.pop();
            res.push_back(t);
            for (auto j : graph[t]) {
                if (!--degree[j]) q.push(j);
            }
        }
        return res;
    }
};

•第二种:采用dfs。需要一个res数组纪录dfs的路径上的节点,用于判断环的存在。而visited数组责纪录dfs中访问过的节点。而其reverse(res)就是上课顺序。

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<unordered_set<int>> graph(numCourses);
        for (auto i : prerequisites) {
            graph[i.second].insert(i.first);
        }
        vector<bool> onpath(numCourses,false), visited(numCourses,false);
        vector<int> res;
        for (int i = 0; i < numCourses; i++) {
            if (!visited[i] && dfs(graph,i,onpath,visited,res)) return {};
        }
        reverse(res.begin(),res.end());//注意得到的结果要逆序
        return res;
    }
    bool dfs(vector<unordered_set<int>>& graph, int node, vector<bool>& onpath, vector<bool>& visited, vector<int>& toposort) {
        if(visited[node]) return false;
        onpath[node]=visited[node] = true;
        for (auto j : graph[node]) {
            if (onpath[j] || dfs(graph,j,onpath,visited,toposort)) return true;
        }
        toposort.push_back(node);
        return onpath[node]=false;
    }
};

注意: 特殊情况输入numCourses = 1,prereqisities为空数组时,答案为[0],只有1个节点,并没有边的存在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值