1. class Solution {
    2. public boolean canFinish(int numCourses, int[][] prerequisites) {
    3. //1:初始化
    4. //1.1 初始化出边数组,就是初始化图,建立边的关系
    5. to = new ArrayList<List<Integer>>();
    6. for(int i = 0 ; i < numCourses ; i ++){
    7. to.add(i,new ArrayList<>());
    8. }
    9. // 1.2 初始化统计图的入度的数组
    10. inDeg = new int[numCourses];
    11. // 1.3 记录BFS中,修过了那些课程
    12. List<Integer> lesson = new ArrayList<>();
    13. for(int[] pre : prerequisites){
    14. //根据题意,第一个是ai第二个是bi
    15. int ai = pre[0];
    16. int bi = pre[1];
    17. //如果想修ai要先修bi的话,要从bi -> ai 建边
    18. to.get(bi).add(ai);
    19. //当加了一条边,是指向ai的,则入度统计里,ai + 1
    20. inDeg[ai] ++;
    21. }
    22. //2: 要执行BFS,广度优先遍历,要先入队
    23. Queue<Integer> queue = new LinkedList<>();
    24. //2.1 遍历所有入度统计数组,当时入度为0的,说明是可以直接修的
    25. // 拓扑排序的第一步:从0入度出发作为起点。
    26. for (int i = 0; i < numCourses; i ++){
    27. //如果入度为0,则放入队列
    28. if(inDeg[i] == 0){
    29. //入队就表示可以修了
    30. queue.add(i);
    31. }
    32. }
    33. //3: 执行BFS
    34. while (!queue.isEmpty()){
    35. // 3.1 x 出队,代表x 可以修了。然后记录x修过了
    36. int x = queue.poll();
    37. lesson.add(x);
    38. // 拓扑排序的第二步:扩展一个点,周围点的入度-1
    39. for(int y : to.get(x)){
    40. inDeg[y]--;
    41. // 拓扑排序的第三步:入度减为0,说明可以入队了
    42. //说明这门课程的全部先修课都被修完了
    43. if(inDeg[y] == 0){
    44. queue.add(y);
    45. }
    46. }
    47. }
    48. //4:返回值。如果修过的课程数 = 全部课程数,则返回true,否则false
    49. return lesson.size() == numCourses;
    50. }
    51. //使用出边数组构建图
    52. private List<List<Integer>> to;
    53. //统计图中点的入度的数组
    54. private int[] inDeg;
    55. }