你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
提示:
输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。
1 <= numCourses <= 10^5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
图的深度优先搜索,或者广度优先搜索。
这道题是第一次做图相关的问题,很多东西都不熟悉,包括邻接表的构建,递归的终止条件,以及图的循环,这里写几个自己当时没有想到的东西。
1. 图的定义,首先与链表或者二叉树不同的是,图没有头结点,如需要遍历图,需要知道图所有的节点,因此图的题目一般是寻找路径,判断是否有环,最短路径之类的问题,不存在遍历图对每个节点做某种操作(个人理解);
2. 邻接表,邻接表是一个二维的链表,实际操作中常常用vector来模拟,它的第一维是图中所有节点的集合,每个节点其后的链表是与这个节点相邻的节点
3. 邻接矩阵,是一个二维的矩阵,与邻接表不同的是,邻接矩阵需要显式的表示所有节点之间两两关系,因此在稀疏图中使用邻接矩阵会有大量的0导致空间浪费
4. 可以通过visit数组的三种状态来判断是否有环,正处于dfs过程中是一种状态,没被访问过是一种状态,访问过是一种状态,如果在dfs过程中访问到了正处于dfs状态的节点,则说明有环。
5. 深度优先遍历是说,在访问到一个新的节点之后,下一个节点继续去访问它的一个没被访问的邻居,直到所有邻居被访问之后,回退到上一个节点,继续访问没被访问过的邻居,大意上是说一条路走到头,在回头走另外一条路
6. 广度优先遍历,需要借助队列,与树的层次遍历类似,在入队的时候进行访问,出队的时候将出队元素的所有邻居节点(未被访问的)入队并访问,本题中,初始化队列的时候要注意入队的是所有入度为零的节点,意思是没有前置要求的课程,之后出队的时候,将它的相邻节点入度减一,代表相邻接点的前置需求被完成了一个,如果入度减为0,则入队表示可以选修该课程,如此以往到最后所有节点的入度是否都小于等于零,或者本题可以使用count计数选修的课程数来判断。
dfs
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
int len = prerequisites.size();
if(len<=1)return true;
vector<vector<int>> adjacent(numCourses);
vector<int>