LeetCode Algorithms 210. Course Schedule II

题目难度: Medium


原题描述:

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


题目大意:

        给出n门课程的相互修完的关系,即要修某门课程必须先修其它某些课程的关系,让你判断是否有可能修完这些课程,如果可能,给出其中一个修课程的顺序。


解题思路:

        这道题是经典的拓扑排序的问题。所谓拓扑排序,就是在一个有向图中按照边的指向顺序来排序,如果A指向B,则A排在B前面;而如果有向图中有环,则不能进行拓扑排序。

      在这道题中,如果修课程2必须先修课程1,则有一条课程1指向课程2的边,按照这样来建一个有向图,再对这个图进行拓扑排序。拓扑排序使用dfs来进行,在dfs中,越先访问完的结点的拓扑序越后,因此第一个访问完的结点的拓扑序在最后,以此类推,在这里访问完一个结点是指它的所有子孙结点全部访问完。在实现中我设置了一个vis数组,vis[i]=0表示未访问过该结点 ;vis[i]=-1表示正在访问该结点(还没访问完) ;vis[i]=1表示已经访问完该结点,且它的所有子孙已经访问完。当一个结点要去访问到一个vis[i]=-1的结点时,就说明这个图有环,不能进行拓扑排序。否则,如果在dfs的过程中没有发现环,则最后返回拓扑序。


时间复杂度分析:

        dfs的时间复杂度为O(n+E),这里E = n-1,因此时间复杂度为O(n),n为树的结点个数。


以下是代码:

/*
vis[i]=0 : 未访问过该结点 
vis[i]=-1 : 正在访问该结点(还没访问完) 
vis[i]=1 : 已经访问完该结点,且它的所有子孙已经访问完 
*/
const int maxn = 100000 + 10;
int vis[maxn];
vector<int> G[maxn];
int topo[maxn];
int topoIndex;

class Solution {
public:
	//返回值:true: 有环
	//        false: 无环 
	bool dfs(int x){
		vis[x] = -1;
		for(int y=0 ; y<G[x].size() ; ++y){
			int to = G[x][y];
			if(vis[to] == -1){
				return true;
			}
			else if(!vis[to] && dfs(to)){
				return true;
			}
		}
		topo[topoIndex--] = x;
		vis[x] = 1;
		return false;
	}
	
    vector<int> findOrder(int numCourses, vector< pair<int, int> >& prerequisites) {
    	vector<int> v;
    	topoIndex = numCourses-1;
        memset(vis,0,sizeof(vis));
        memset(topo,0,sizeof(topo));
        for(int i=0 ; i<numCourses ; ++i){
    		G[i].clear();
		}
		for(int i=0 ; i<prerequisites.size() ; ++i){
		 	int to = prerequisites[i].first;
		 	int from = prerequisites[i].second;
		 	G[from].push_back(to);
		}
		for(int i=0 ; i<numCourses ; ++i){
			if(!vis[i] && dfs(i)){
				return v;
			}
		}
		vector<int> v2(topo, topo+numCourses);
		return v2;
	}
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值