题目描述
你这个学期必须选修 numCourses
门课程,记为 0
到 numCourses - 1
。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites
给出,其中 prerequisites[i] = [ai, bi]
,表示如果要学习课程 ai
则 必须 先学习课程 bi
。
- 例如,先修课程对
[0, 1]
表示:想要学习课程 0
,你需要先完成课程 1
。
请你判断是否可能完成所有课程的学习?如果可以,返回 true
;否则,返回 false
。
示例 1:
1 2 3
| 输入:numCourses = 2, prerequisites = [[1,0]] 输出:true 解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
|
示例 2:
1 2 3
| 输入:numCourses = 2, prerequisites = [[1,0],[0,1]] 输出:false 解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
|
提示:
1 <= numCourses <= 10^5
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i]
中的所有课程对 互不相同
解法
- 深度优先搜索+拓扑排序
- 对于图中的任意一个节点,它在搜索的过程中有三种状态,即:
- 「未搜索」:我们还没有搜索到这个节点;
- 「搜索中」:我们搜索过这个节点,但还没有回溯到该节点,即该节点还没有入栈,还有相邻的节点没有搜索完成);
- 「已完成」:我们搜索过并且回溯过这个节点,即该节点已经入栈,并且所有该节点的相邻节点都出现在栈的更底部的位置,满足拓扑排序的要求。
- 我们将当前搜索的节点u标记为「搜索中」,遍历该节点的每一个相邻节点 v:
- 如果 v 为「未搜索」,那么我们开始搜索 v,待搜索完成回溯到 u;
- 如果 v 为「搜索中」,那么我们就找到了图中的一个环,因此是不存在拓扑排序的;
- 如果 v 为「已完成」,那么说明 v 已经在栈中了,而 u 还不在栈中,因此 u无论何时入栈都不会影响到 (u, v) 之前的拓扑关系,以及不用进行任何操作。
- 当 u的所有相邻节点都为「已完成」时,我们将 u 放入栈中,并将其标记为「已完成」。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| class Solution { List<List<Integer>> edges; boolean valid = true; int[] visited; public boolean canFinish(int numCourses, int[][] prerequisites) { edges = new ArrayList<>(); for (int i = 0; i < numCourses; i++) { edges.add(new ArrayList<Integer>()); } visited = new int[numCourses];
for (int[] info : prerequisites) { edges.get(info[1]).add(info[0]); }
for (int i = 0; i < numCourses && valid; i++) { if (visited[i] == 0) { dfs(i); } }
return valid; }
private void dfs(int i) { visited[i] = 1; for (int num : edges.get(i)) { if (visited[num] == 0) { dfs(num); if (!valid) { return; } } else if (visited[num] == 1) { valid = false; return; } } visited[i] = 2; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) { int[] input = new int[numCourses]; int count = 0; LinkedList<Integer> queue = new LinkedList<>(); for(int[] pre:prerequisites){ input[pre[0]]++; } for(int i=0;i<numCourses;i++){ if(input[i]==0){ queue.addLast(i); } }
while(!queue.isEmpty()){ int node = queue.removeFirst(); count++; for(int[] pre:prerequisites){ if(pre[1]==node){ input[pre[0]]--; if(input[pre[0]]==0){ queue.addLast(pre[0]); } } } }
return count==numCourses; } }
|
来源:力扣(LeetCode)
链接:207. 课程表 - 力扣(LeetCode)