深度优先搜索
广度优先搜索
图
拓扑排序
题目描述
你这个学期必须选修 numCourses
门课程,记为 0
到 numCourses - 1
。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites
给出,其中 prerequisites[i] = [ai , bi ]
,表示如果要学习课程 ai
则 必须 先学习课程 bi
。
例如,先修课程对 [0, 1]
表示:想要学习课程 0
,你需要先完成课程 1
。
请你判断是否可能完成所有课程的学习?如果可以,返回 true
;否则,返回 false
。
示例 1:
输入: numCourses = 2, prerequisites = [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入: numCourses = 2, prerequisites = [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai , bi < numCourses
prerequisites[i]
中的所有课程对 互不相同
解法
方法一:拓扑排序
对于本题,我们可以将课程看作图中的节点,先修课程看作图中的边,那么我们可以将本题转化为判断有向图中是否存在环。
具体地,我们可以使用拓扑排序的思想,对于每个入度为 $0$ 的节点,我们将其出度的节点的入度减 $1$,直到所有节点都被遍历到。
如果所有节点都被遍历到,说明图中不存在环,那么我们就可以完成所有课程的学习;否则,我们就无法完成所有课程的学习。
时间复杂度 $O(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别为课程数和先修课程数。
Python3 Java C++ Go TypeScript Rust C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 class Solution :
def canFinish ( self , numCourses : int , prerequisites : List [ List [ int ]]) -> bool :
g = defaultdict ( list )
indeg = [ 0 ] * numCourses
for a , b in prerequisites :
g [ b ] . append ( a )
indeg [ a ] += 1
cnt = 0
q = deque ( i for i , x in enumerate ( indeg ) if x == 0 )
while q :
i = q . popleft ()
cnt += 1
for j in g [ i ]:
indeg [ j ] -= 1
if indeg [ j ] == 0 :
q . append ( j )
return cnt == numCourses
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 class Solution {
public boolean canFinish ( 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 cnt = 0 ;
while ( ! q . isEmpty ()) {
int i = q . poll ();
++ cnt ;
for ( int j : g [ i ] ) {
if ( -- indeg [ j ] == 0 ) {
q . offer ( j );
}
}
}
return cnt == numCourses ;
}
}
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 class Solution {
public :
bool canFinish ( int numCourses , vector < vector < int >>& prerequisites ) {
vector < 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 );
}
}
int cnt = 0 ;
while ( ! q . empty ()) {
int i = q . front ();
q . pop ();
++ cnt ;
for ( int j : g [ i ]) {
if ( -- indeg [ j ] == 0 ) {
q . push ( j );
}
}
}
return cnt == numCourses ;
}
};
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 func canFinish ( numCourses int , prerequisites [][] int ) bool {
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 , x := range indeg {
if x == 0 {
q = append ( q , i )
}
}
cnt := 0
for len ( q ) > 0 {
i := q [ 0 ]
q = q [ 1 :]
cnt ++
for _ , j := range g [ i ] {
indeg [ j ] --
if indeg [ j ] == 0 {
q = append ( q , j )
}
}
}
return cnt == numCourses
}
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 function canFinish ( numCourses : number , prerequisites : number [][]) : boolean {
const g : number [][] = new Array ( numCourses ). fill ( 0 ). map (() => []);
const indeg : number [] = new Array ( numCourses ). fill ( 0 );
for ( const [ a , b ] of prerequisites ) {
g [ b ]. push ( a );
indeg [ a ] ++ ;
}
const q : number [] = [];
for ( let i = 0 ; i < numCourses ; ++ i ) {
if ( indeg [ i ] == 0 ) {
q . push ( i );
}
}
let cnt = 0 ;
while ( q . length ) {
const i = q . shift () ! ;
cnt ++ ;
for ( const j of g [ i ]) {
if ( -- indeg [ j ] == 0 ) {
q . push ( j );
}
}
}
return cnt == numCourses ;
}
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 use std :: collections :: VecDeque ;
impl Solution {
#[allow(dead_code)]
pub fn can_finish ( num_course : i32 , prerequisites : Vec < Vec < i32 >> ) -> bool {
let num_course = num_course as usize ;
// The graph representation
let mut graph : Vec < Vec < i32 >> = vec! [ vec! []; num_course ];
// Record the in degree for each node
let mut in_degree_vec : Vec < i32 > = vec! [ 0 ; num_course ];
let mut q : VecDeque < usize > = VecDeque :: new ();
let mut count = 0 ;
// Initialize the graph & in degree vector
for p in & prerequisites {
let ( from , to ) = ( p [ 0 ], p [ 1 ]);
graph [ from as usize ]. push ( to );
in_degree_vec [ to as usize ] += 1 ;
}
// Enqueue the first batch of nodes with in degree 0
for i in 0 .. num_course {
if in_degree_vec [ i ] == 0 {
q . push_back ( i );
}
}
// Begin the traverse & update through the graph
while ! q . is_empty () {
// Get the current node index
let index = q . front (). unwrap (). clone ();
// This course can be finished
count += 1 ;
q . pop_front ();
for i in & graph [ index ] {
// Update the in degree for the current node
in_degree_vec [ * i as usize ] -= 1 ;
// See if can be enqueued
if in_degree_vec [ * i as usize ] == 0 {
q . push_back ( * i as usize );
}
}
}
count == num_course
}
}
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 public class Solution {
public bool CanFinish ( int numCourses , int [][] prerequisites ) {
var g = new List < int > [ numCourses ];
for ( int i = 0 ; i < numCourses ; ++ i ) {
g [ i ] = new List < int > ();
}
var indeg = new int [ numCourses ];
foreach ( var p in prerequisites ) {
int a = p [ 0 ], b = p [ 1 ];
g [ b ]. Add ( a );
++ indeg [ a ];
}
var q = new Queue < int > ();
for ( int i = 0 ; i < numCourses ; ++ i ) {
if ( indeg [ i ] == 0 ) {
q . Enqueue ( i );
}
}
var cnt = 0 ;
while ( q . Count > 0 ) {
int i = q . Dequeue ();
++ cnt ;
foreach ( int j in g [ i ]) {
if ( -- indeg [ j ] == 0 ) {
q . Enqueue ( j );
}
}
}
return cnt == numCourses ;
}
}