LeetCode -- 207. Course Schedule(课程计划)

6 篇文章 0 订阅
6 篇文章 0 订阅


一、原文

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, is it possible for you to finish all courses?

Example 1:

Input: 2, [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.

Example 2:

Input: 2, [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0, and to take course 0 you should
also have finished course 1. So it is impossible.

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]

给定课程总数和前提条件数对,你是否能完成所有课程?

balabala~


三、分析


3.1 利用拓扑排序

从题意中可以明显看出这是一个(有向)图的问题,再细想一下就会发现这是拓扑排序问题。

所以用一个最简单的方法就是找出所有入度为 0 的结点,然后从它们开始遍历整个图,再遍历过程中对其他结点的入度进行减的操作,如果减到0就入栈(或入队),最后判断是否有入度不为0的存在,如果有,就说明图中出现了环,也就是说此例为FALSE。

当然,在一开始要对输入数据进行一下处理,将数对转换为图的邻接表形式,此处的邻接表是用二维矩阵表示,第一个下标表示尾,存储的值就是与该尾结点相连的头结点(有向图中的边)。


3.2 DFS

既然LeetCode将这题划分在DFS内,那就用DFS来解一下。

首先,要判断能不能完成所有课程,转换一下问题就是判断是不是存在环。如果存在环说明不能完成所有课程,反之就是可以完成所有课程。

那么如何去实现代码呢?

首先,对输入的数对我们进行一些处理(因为它太杂乱了),将其变得适合我们去解决问题的数据形式。

既然我们是判断是否存在环,那我们就得对每门课进行DFS,当然得对每门课进行标记,不然如何知道这门课是否被访问过,这样就得有两个状态:访问过和未访问过。但是两个状态不足以我们判断环的存在,比如 [0, 1], [1, 0],这个用两个状态是无法判断环的存在,所以得需要第三个状态来表示这个结点正在被访问。(此处这个关系书写语言描述我实在不知道咋写好,大家可以自己在纸上模拟一下 T_T)。

具体的见代码吧,代码说话!


四、AC代码


4.1 利用拓扑排序

class Solution {
public:
	bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
		if (prerequisites.size() < 2) {
			return true;
		}
		
		vector<vector<int>> adjTable(numCourses);
		vector<int> in(numCourses, 0);
		for (int i = 0; i < prerequisites.size(); ++i) {
			adjTable[prerequisites[i][1]].push_back(prerequisites[i][0]);
			in[prerequisites[i][0]]++;
		}

		stack<int> start;
		for (int i = 0; i < numCourses; ++i) {
			if (in[i] == 0) {
				start.push(i);
			}
		}

		while (!start.empty()) {
			int s = start.top();
			start.pop();
			for (int i = 0; i < adjTable[s].size(); ++i) {
				in[adjTable[s][i]]--;
				if (!in[adjTable[s][i]]) {
					start.push(adjTable[s][i]);
				}
			}
		}

		for (int i = 0; i < numCourses; ++i) {
			if (in[i] != 0) {
				return false;
			}
		}
		return true;
	}
};

4.2 DFS

class Solution {
public:
	bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
		if (prerequisites.size() < 2) {
			return true;
		}
		
		vector<vector<int>> adjTable(numCourses);
		// 0 表示未访问
		// 1 表示正在访问,此处是为了判断循环
		// 2 表示访问过了
		vector<int> visited(numCourses, 0);
		for (int i = 0; i < prerequisites.size(); ++i) {
			adjTable[prerequisites[i][1]].push_back(prerequisites[i][0]);
		}

		for (int i = 0; i < numCourses; ++i) {
			if (visited[i] == 0 && !dfs(i, visited, adjTable)) {
				return false;
			}
		}

		return true;
	}

	bool dfs(int course, vector<int>& visited, vector<vector<int>>& adjTable) {
		visited[course] = 1;
		for (int c : adjTable[course]) {
			if (visited[c] == 1) {
				return false;
			}
			if (!dfs(c, visited, adjTable)) {
				return false;
			}
		}
		visited[course] = 2;
		return true;
	}
};

如有错误之处,敬请指出!大家共勉!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值