207.课程表

69 阅读2分钟

题目:
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
算法:

方法一:DFS
本质上是判断DAG是否存在环,我们先构建邻接表,表明从preRequireCourse->curCourse的关系。然后对每一个课程进行遍历,用flag数组标识课程是否已经查找过了,本轮查找过了1,其他轮查找过了-1,未查找0

func canFinish(numCourses int, prerequisites [][]int) bool {
	adjacency := make([][]int, numCourses)
	flag := make([]int, numCourses)
	for i := range prerequisites {
		adjacency[prerequisites[i][1]] = append(adjacency[prerequisites[i][1]], prerequisites[i][0])
	}

	var dfs func(course int) bool
	dfs = func(course int) bool {
		if flag[course] == 1 {
			return false
		}
		if flag[course] == -1 {
			return true
		}
		flag[course] = 1
		for j := range adjacency[course] {
			if !dfs(adjacency[course][j]) {
				return false
			}
		}
		flag[course] = -1
		return true
	}
        // 这里其实只遍历邻接表中存在的关系课程就可以,即adjacency中values数组长度大于0的元素。
	for i := 0; i < numCourses; i ++ {
		if !dfs(i) {
			return false
		}
	}
	return true
}

方法二:BFS
使用三个数据结构入度数组inDegree(保存每个顶点的入度),邻接表:adjency(表示前置课程和后续课程的依赖关系),队列queue(保存入度为0的顶点,队列中的课程意味着可以选择)。

初始化inDegree和adjency后,将入度为0的课程加入队列(选课),该课程选完之后 count++,后置课程的入度-1,如果课程的入度为0了,则加入队列queue。

最后比较count是否等于numCourses,即是否所有的可都可以选到。

func canFinish(numCourses int, prerequisites [][]int) bool {
	// index前置依赖课程,value完成前置之后可选择的后续课程
	adjacency := make([][]int, numCourses)
	inDegree := make([]int, numCourses)
	count := 0
	// 初始化inDegree, 初始化adjacency
	for _, req := range prerequisites {
		adjacency[req[1]] = append(adjacency[req[1]], req[0])
		inDegree[req[0]] ++
	}
	queue := make([]int, 0)
	for course, inDegree := range inDegree {
		if inDegree == 0 {
			queue = append(queue, course)
			count ++
		}
	}

	// 入队列queue
	for len(queue) != 0 {
		preCourse := queue[0]
		queue = queue[1:]
		for _, afterCourse := range adjacency[preCourse] {
			inDegree[afterCourse] --
			if inDegree[afterCourse] == 0 {
				queue = append(queue, afterCourse)
				count ++
			}
		}
	}
	return count == numCourses
}

优雅!