2025年- G34-Lc108-207. 课程计划--java版
1.题目描述

 中文:
 课程安排 (Course Schedule) - 题目翻译
 你需要完成 numCourses 门课程,课程编号从 0 到 numCourses - 1。
你会得到一个 前置课程要求数组 prerequisites,其中 prerequisites[i] = [a_i, b_i] 表示:
如果你想选修课程 a_i,你必须先完成课程 b_i。
要求
 如果你可以完成所有课程,返回 true;否则,返回 false。
2.思路

 
 
 

 
 
 
 

 
 例子2:



 
 例子2:
 
 
 
 
3.代码实现
class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> gra=new ArrayList<>();
        for(int i=0;i<numCourses;i++)
        {
            gra.add(new ArrayList<>());//构建prerequisites的二维数组, // gra 现在是 [[ ]],// gra 现在是 [[ ], [ ]]
        }
        for(int[] pre:prerequisites)
        {
            gra.get(pre[1]).add(pre[0]);///建立先修关系,返回一个新的先修课程的二维数组[[1],[2],[]]
        }
        //设计一个数组,表示当前点的元素是已访问过
        int[] visited=new int[numCourses];// 所有课程初始状态都是 0(未访问)
        //3.遍历所有课程,检查是否有环
        for(int i=0;i<numCourses;i++)
        {
            if(dfs(gra,visited,i))
            {
                return false;
            }
        }
        return true;
    }
        //4.写个递归调用,用来遍历课程。
        //0: 未访问(Not visited)——该节点尚未被访问,或者它的所有邻居都已经被遍历过。
        //1: 访问中(Visiting)——该节点正在被访问,或者它位于当前递归路径上。这意味着我们已经进入这个节点,但它的所有邻居尚未被访问。
        //2: 已访问(Visited)——该节点已经被完全遍历过,即它的所有邻居已经访问过,且没有发现环。
         private boolean dfs(List<List<Integer>> gra, int[] visited, int course) {
            if(visited[course]==1)
            return true;
            if(visited[course]==2)
            return false;// 该课程已检查过,无环
            // 进入递归,标记为“访问中”
            visited[course]=1;
            for(int next:gra.get(course))//遍历 course 之后的课程(它的直接后继课程)
            {
             if(dfs(gra,visited,next))
             {
                return true;
             }
            } 
          // 递归结束,标记为“已完成”
           visited[course] = 2;// 【回溯】标记当前课程检查完毕,后续递归不会再访问它
            return false;// 没有发现环,返回 false
         }
           
    
}
