根据课程之间的关系构造一个有向图,题目要求求解是否能按照顺序学完所有课程,即判断这个有向图是否是有向无环图,如果是求出这个图的拓扑排序,如果不是返回[0]
求这个图的拓扑排序可以按照以下思路:
对于每个节点都有三种状态:
- 未搜索
- 搜索中:正在搜索这个节点的相邻节点还没回溯回来
- 已完成:相邻节点都搜索结束并已经入栈,该节点搜索完成,入栈
对于搜索中的节点u
,遍历其相邻节点v
,存在以下情况:
v
未搜索:开始搜索v
v
搜索中:和u
矛盾了,存在环,无拓扑排序v
已完成:v
已入栈,回溯u
直到所有节点入栈(已完成),从栈顶到栈底的排列即为拓扑排序结果。
这道题中使用int[]
和index
来模拟一个栈。
class Solution {List<List<Integer>> edges;int[] visited;int[] result;boolean hasCircle = false;int index; // 用数组实现栈,用一个index定位public int[] findOrder(int numCourses, int[][] prerequisites) {edges = new ArrayList<List<Integer>>();for (int i = 0; i < numCourses; ++i) {edges.add(new ArrayList<Integer>());}for (int[] info : prerequisites) {edges.get(info[1]).add(info[0]);}visited = new int[numCourses];result = new int[numCourses];index = numCourses - 1;for (int i = 0; i < numCourses && !hasCircle; ++i) {if (visited[i] == 0) {dfs(i);}}if (hasCircle) return new int[0];return result;}public void dfs(int node) {visited[node] = 1;for (int n : edges.get(node)) {if (visited[n] == 0) {dfs(n);if (hasCircle) return;}else if (visited[n] == 1) {hasCircle = true;return;}}visited[node] = 2;result[index--] = node;}
}
很有趣的一点是:
edges = new ArrayList<List<Integer>>();
如果去掉了List<Integer>
速度会变慢。