210. Course Schedule II - Medium

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.

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].

Code

这便是赤裸裸的拓扑排序了,改一改Course Schedule的代码即可,也就是在“黑色状态”位置把遍历玩的点输出。直接上代码:

class Solution {
private:
    vector< vector<int> > V;
    vector<int> ans, vis; // -1访问过一次,0没访问过,1访问完了 
    bool dfs(int u) {
        int v, i;
        vis[u] = -1;
        for (i=0; i<V[u].size(); i++) {
            v = V[u][i];
            if (!vis[v]) dfs(v);
            if (vis[v] == -1) return false;
        }
        vis[u] = 1;
        ans.push_back(u);
        return true;
    }
public:
    vector<int> findOrder(int n, vector< pair<int, int> >& edges) {
        int i;
        V.resize(n);
        vis.resize(n);
        for(int i = 0; i < edges.size(); ++i)
            V[edges[i].first].push_back(edges[i].second);
        for (i=0; i<n; i++) vis[i] = 0;
        for (i=0; i<n; i++)
            if (!vis[i]) {
                if(!dfs(i))  {
                    vector<int> temp;
                    return temp;
                }
            }
        return ans;
    }
};

Summary

关于逆序输出的问题?

在一般的图问题中,[0,1]表示从0到1的有向边,并且0的拓扑序优先于1,所以拓扑序与深度遍历的顺序是反过来的。而本题的描述中[0, 1]表示的含义恰好相反,因此只需要按照这种反的边存储图,最后往ans里push_back。假如是一般情况,我们可以特意逆过来存储边以避免逆序输出,或者在最后用ans.insert(ans.begin(), u);这样的操作往前插。

从拓扑排序到图的遍历

目前我看到图的题目就发怵,决定搞清楚BFS和DFS的实现先,它们是图论算法的基础。算法思想是好掌握的,另外我总结了以下几点:
一、图的遍历不过是找一种顺序,经过每个点一次且仅一次,从哪个点开始真的没关系,图是有向还是无向也没关系。
二、用哪种数据结构存储,对实现难度影响不大,只是会影响到算法效率。邻接矩阵是O(n^2),邻接链表是O(VE),稠密图应当用矩阵,稀疏图用表。
三、DFS有递归和非递归两种版本:
递归版实现可以说非常简单漂亮了,对每个未被访问节点调用dfs遍历。
而非递归版要用栈保存一条纵深的路径,遍历完子节点再往上回溯。
四、BFS就一种实现:层次遍历,用队列循环处理。
五、假如图中可能有多个连通分量,只需要在一次遍历结束后判断一下是否所有节点都被访问过了,没有的话从下一个没被访问的节点开始遍历即可——对BFS、DFS都适用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值