comments: true
edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20113.%20%E8%AF%BE%E7%A8%8B%E9%A1%BA%E5%BA%8F/README.md
劍指 Offer II 113. 課程順序
題目描述
現在總共有 numCourses
?門課需要選,記為?0
?到?numCourses-1
。
給定一個數組?prerequisites
,它的每一個元素?prerequisites[i]
?表示兩門課程之間的先修順序。?例如?prerequisites[i] = [ai, bi]
?表示想要學習課程 ai
?,需要先完成課程 bi
?。
請根據給出的總課程數 ?numCourses
和表示先修順序的?prerequisites
?得出一個可行的修課序列。
可能會有多個正確的順序,只要任意返回一種就可以了。如果不可能完成所有課程,返回一個空數組。
?
示例?1:
輸入: numCourses = 2, prerequisites = [[1,0]] 輸出:[0,1]
解釋:?總共有 2 門課程。要學習課程 1,你需要先完成課程 0。因此,正確的課程順序為[0,1] 。
示例?2:
輸入: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] 輸出:[0,1,2,3] or [0,2,1,3]
解釋:?總共有 4 門課程。要學習課程 3,你應該先完成課程 1 和課程 2。并且課程 1 和課程 2 都應該排在課程 0 之后。因此,一個正確的課程順序是?[0,1,2,3]
。另一個正確的排序是?[0,2,1,3]
。
示例 3:
輸入: numCourses = 1, prerequisites = []
輸出: [0]
解釋:?總共 1 門課,直接修第一門課就可。
?
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= numCourses * (numCourses - 1)
prerequisites[i].length == 2
0 <= ai, bi < numCourses
ai != bi
prerequisites
?中不存在重復元素
?
注意:本題與主站 210?題相同:https://leetcode.cn/problems/course-schedule-ii/
解法
方法一:拓撲排序
拓撲排序的思路是,先統計每個節點的入度,然后從入度為 0 的節點開始,依次刪除這些節點,同時更新與這些節點相連的節點的入度,直到所有節點都被刪除。
這里使用隊列來存儲入度為 0 的節點,每次從隊列中取出一個節點,將其加入結果數組中,然后遍歷與這個節點相連的節點,將這些節點的入度減 1,如果減 1 后入度為 0,則將這些節點加入隊列中。
最后判斷結果數組的長度是否等于節點的個數,如果等于則返回結果數組,否則返回空數組。
時間復雜度 O ( n + m ) O(n + m) O(n+m),空間復雜度 O ( n + m ) O(n + m) O(n+m)。其中 n n n 和 m m m 分別是節點的個數和邊的個數。
Python3
class Solution:def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:graph=defaultdict(list)indg={} #其實目的還是為bfs第一層服務的for i in range(numCourses): #【注意】初始化,要不然第一層為空indg[i]=0 for b,a in prerequisites:graph[a].append(b)indg[b]+=1# 第一層q=deque()for node,ind in indg.items():if ind==0:q.append(node)print(q,indg)#bfsres=[]while q:for _ in range(len(q)):cur=q.popleft()res.append(cur)for nx in graph[cur]:indg[nx]-=1if indg[nx]==0:q.append(nx)return res if len(res)==numCourses else []
Java
class Solution {public int[] findOrder(int numCourses, int[][] prerequisites) {List<Integer>[] g = new List[numCourses];Arrays.setAll(g, k -> new ArrayList<>());int[] indeg = new int[numCourses];for (var p : prerequisites) {int a = p[0], b = p[1];g[b].add(a);++indeg[a];}Deque<Integer> q = new ArrayDeque<>();for (int i = 0; i < numCourses; ++i) {if (indeg[i] == 0) {q.offer(i);}}int[] ans = new int[numCourses];int cnt = 0;while (!q.isEmpty()) {int i = q.poll();ans[cnt++] = i;for (int j : g[i]) {if (--indeg[j] == 0) {q.offer(j);}}}return cnt == numCourses ? ans : new int[0];}
}
C++
class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<int> g[numCourses];vector<int> indeg(numCourses);for (auto& p : prerequisites) {int a = p[0], b = p[1];g[b].push_back(a);++indeg[a];}queue<int> q;for (int i = 0; i < numCourses; ++i) {if (indeg[i] == 0) {q.push(i);}}vector<int> ans;while (q.size()) {int i = q.front();q.pop();ans.push_back(i);for (int j : g[i]) {if (--indeg[j] == 0) {q.push(j);}}}return ans.size() == numCourses ? ans : vector<int>();}
};
Go
func findOrder(numCourses int, prerequisites [][]int) []int {g := make([][]int, numCourses)indeg := make([]int, numCourses)for _, p := range prerequisites {a, b := p[0], p[1]g[b] = append(g[b], a)indeg[a]++}q := []int{}for i, v := range indeg {if v == 0 {q = append(q, i)}}ans := []int{}for len(q) > 0 {i := q[0]q = q[1:]ans = append(ans, i)for _, j := range g[i] {indeg[j]--if indeg[j] == 0 {q = append(q, j)}}}if len(ans) == numCourses {return ans}return []int{}
}
TypeScript
function findOrder(numCourses: number, prerequisites: number[][]): number[] {const g: number[][] = Array.from({ length: numCourses }, () => []);const indeg: number[] = Array(numCourses).fill(0);for (const [a, b] of prerequisites) {g[b].push(a);++indeg[a];}const q: number[] = indeg.map((v, i) => (v === 0 ? i : -1)).filter(v => v !== -1);const ans: number[] = [];while (q.length) {const i = q.pop()!;ans.push(i);for (const j of g[i]) {if (--indeg[j] === 0) {q.push(j);}}}return ans.length === numCourses ? ans : [];
}
C#
public class Solution {public int[] FindOrder(int numCourses, int[][] prerequisites) {List<int>[] g = new List<int>[numCourses];for (int i = 0; i < numCourses; i++) {g[i] = new List<int>();}int[] indeg = new int[numCourses];foreach (var p in prerequisites) {int a = p[0], b = p[1];g[b].Add(a);++indeg[a];}Queue<int> q = new Queue<int>();for (int i = 0; i < numCourses; ++i) {if (indeg[i] == 0) {q.Enqueue(i);}}int[] ans = new int[numCourses];int cnt = 0;while (q.Count > 0) {int i = q.Dequeue();ans[cnt++] = i;foreach (int j in g[i]) {if (--indeg[j] == 0) {q.Enqueue(j);}}}return cnt == numCourses ? ans : new int[0];}
}
Swift
class Solution {func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] {var graph = Array(repeating: [Int](), count: numCourses)var indegree = Array(repeating: 0, count: numCourses)for prereq in prerequisites {let course = prereq[0]let prereqCourse = prereq[1]graph[prereqCourse].append(course)indegree[course] += 1}var queue = [Int]()for i in 0..<numCourses {if indegree[i] == 0 {queue.append(i)}}var order = [Int]()while !queue.isEmpty {let course = queue.removeFirst()order.append(course)for nextCourse in graph[course] {indegree[nextCourse] -= 1if indegree[nextCourse] == 0 {queue.append(nextCourse)}}}return order.count == numCourses ? order : []}
}