【LeetCode】hot100— 207. 课程表_BFS


你这个学期必须选修 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 。这是可能的。

1 - 思路

image.png

  • 题目考察的最终结果是,所用课程是否学完,则所有图的结点是否已经访问到,若可以通过图的结构访问完,证明可以学完所有课程。
  • 解法:为有向图建立拓扑排序
  • 记录结点的 入度 和 出度
  • 入度维护:通过一个 **int** 数组维护结点的入度
  • 出度维护:通过 List<List<Integer>> outNode 来维护出图中所有节点的后继结点

2 - 实现

BFS 过程 模拟

image.png
构建依赖图

  1. 初始化outNode和inNode。对于4个课程(编号0到3),outNode初始化为4个空列表,inNode初始化为4个0。
  2. 根据先决条件更新outNode和inNode:
  • 对于[1,0],将1添加到0的后继课程列表中,inNode[1]加1。
  • 对于[2,0],将2添加到0的后继课程列表中,inNode[2]加1。
  • 对于[3,1],将3添加到1的后继课程列表中,inNode[3]加1。
  • 对于[3,2],将3添加到2的后继课程列表中,inNode[3]再加1。
  • 此时,outNode和inNode如下:
  • outNode = [[1, 2], [3], [3], []]:课程0的后继课程是1和2,课程1和2的后继课程是3,课程3没有后继课
  • inNode = [0, 1, 1, 2]:课程0没有先决条件,课程1和2各有一个先决条件,课程3有两个先决条件。

执行BFS

  1. 将所有入度为0的课程(即没有先决条件的课程)加入队列。这里是课程0。
  2. 开始BFS过程:
  • 从队列中取出课程0,将visited计数加1。
  • 查看课程0的后继课程(1和2),将它们的入度减1。此时,inNode = [0, 0, 0, 2]。
  • 由于课程1和2的入度变为0,将它们加入队列。
  • 接下来,队列中有课程1和2。依次取出这两个课程,对于每个课程,重复上述减少入度并检查后继课程的过程。
  • 取出课程1,将visited计数加1,减少课程3的入度(inNode[3]变为1)。
  • 取出课程2,将visited计数加1,再次减少课程3的入度(inNode[3]变为0),此时课程3的入度为0,将其加入队列。
  • 最后,取出课程3,将visited计数加1。此时,所有课程的入度都为0,且visited计数为4,等于课程总数。
⭐课程表 —— BFS 思路如下

image.png

class Solution {

    List<List<Integer>> outNode; // 出度集合
    int[] inNode; // 入度个数
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // 初始化出度集合
        outNode = new ArrayList<>();
        for(int i = 0 ; i<numCourses;i++){
            outNode.add(new ArrayList<>());
        }        
        // 加入出度结点
        // 初始化入度数组
        inNode = new int[numCourses];
        for(int[] num:prerequisites){
            outNode.get(num[1]).add(num[0]);
            inNode[num[0]]++;
        }

        Queue<Integer> queue = new LinkedList<>();
        // 添加入度为 0 的元素到 queue 代表起始点
        for(int i = 0 ; i < inNode.length ;i++){
            if(inNode[i]==0){
                queue.offer(i);
            }
        }

        int visited = 0;
        while(!queue.isEmpty()){
            int u = queue.poll();
            for(int v : outNode.get(u)){
                // 遍历到 v 证明可以学习到v
                // 此时 v 入度要减少
                inNode[v]--;
                if(inNode[v]==0){
                    queue.offer(v);
                }
            }
            visited++;
        }
        return visited == numCourses;
    }
}

3 - ACM模式

public class hot52_canFinish {

    static List<List<Integer>> outNode; // 出度集合
    static int[] inNode; // 入度个数
    public static boolean canFinish(int numCourses, int[][] prerequisites) {
        // 初始化出度集合
        outNode = new ArrayList<>();
        for(int i = 0 ; i<numCourses;i++){
            outNode.add(new ArrayList<>());
        }
        // 加入出度结点
        // 初始化入度数组
        inNode = new int[numCourses];
        for(int[] num:prerequisites){
            outNode.get(num[1]).add(num[0]);
            inNode[num[0]]++;
        }

        Queue<Integer> queue = new LinkedList<>();
        // 添加入度为 0 的元素到 queue 代表起始点
        for(int i = 0 ; i < inNode.length ;i++){
            if(inNode[i]==0){
                queue.offer(i);
            }
        }

        int visited = 0;
        while(!queue.isEmpty()){
            int u = queue.poll();
            for(int v : outNode.get(u)){
                // 遍历到 v 证明可以学习到v
                // 此时 v 入度要减少
                inNode[v]--;
                if(inNode[v]==0){
                    queue.offer(v);
                }
            }
            visited++;
        }
        return visited == numCourses;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("输入课程数");
        int numcourses = sc.nextInt();


        System.out.println("输入二维数组 行 row");
        int row = sc.nextInt();


        int col = 2;
        System.out.println("输入课程关系");
        int[][] grid = new int[row][col];
        for(int i = 0; i < row;i++){
            for (int j = 0; j < col;j++){
                grid[i][j] = sc.nextInt();
            }
        }

        System.out.println("能否完成完课程"+canFinish(numcourses,grid));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值