public int[] findOrder(int numCourses, int[][] prerequisites) { edges = new ArrayList<List<Integer>>(); for (int i = 0; i < numCourses; ++i) { edges.add(new ArrayList<Integer>()); } visited = new int[numCourses]; result = new int[numCourses]; index = numCourses - 1; 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); } } if (!valid) { return new int[0]; } // 如果没有环,那么就有拓扑排序 return result; }
queue<int> q; // 将所有入度为 0 的节点放入队列中 for (int i = 0; i < numCourses; ++i) { if (indeg[i] == 0) { q.push(i); } }
while (!q.empty()) { // 从队首取出一个节点 int u = q.front(); q.pop(); // 放入答案中 result.push_back(u); for (int v: edges[u]) { --indeg[v]; // 如果相邻节点 v 的入度为 0,就可以选 v 对应的课程了 if (indeg[v] == 0) { q.push(v); } } }
//Java class Solution { // 存储有向图 List<List<Integer>> edges; // 存储每个节点的入度 int[] indeg; // 存储答案 int[] result; // 答案下标 int 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>()); } indeg = new int[numCourses]; result = new int[numCourses]; index = 0; for (int[] info : prerequisites) { edges.get(info[1]).add(info[0]); ++indeg[info[0]]; }
Queue<Integer> queue = new LinkedList<Integer>(); // 将所有入度为 0 的节点放入队列中 for (int i = 0; i < numCourses; ++i) { if (indeg[i] == 0) { queue.offer(i); } }
while (!queue.isEmpty()) { // 从队首取出一个节点 int u = queue.poll(); // 放入答案中 result[index++] = u; for (int v: edges.get(u)) { --indeg[v]; // 如果相邻节点 v 的入度为 0,就可以选 v 对应的课程了 if (indeg[v] == 0) { queue.offer(v); } } }
if (index != numCourses) { return new int[0]; } return result; } }
复杂度分析
时间复杂度: O(n+m),其中 n 为课程数,m 为先修课程的要求数。这其实就是对图进行广度优先搜索的时间复杂度。