【LeetCode-中等题】207. 课程表

文章目录

    • 题目
    • [方法一:bfs广度优先 + 有向图的拓扑排序(入度)](#方法一:bfs广度优先 + 有向图的拓扑排序(入度))
    • [方法二:dfs 深度优先搜索](#方法二:dfs 深度优先搜索)

题目


此题就可以转换为,求一个有向图是否存在环;
存在环,拓扑排序得出的结果是不完整的,
如果不存在环,则拓扑排序得出的结果就是完整的节点值(拓扑排序不唯一)

怎么判断有环和无环,就看从任意一个点出发,按照箭头方向走,会不会走到以及走过的地方,如果是就是有环

方法一:bfs广度优先 + 有向图的拓扑排序(入度)

思路:将题目中的 prerequisites = [[1,0],[2,0],[3,1],[4,3],[4,2],[5,4]]数组,

按照规则prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

画出有向图:

解题步骤:

  1. 先将题目的数组按照题目意思,转为有向图

  2. 构造入度数组(里面包括每个课程的入度) 课程编号 = 数组下标 数组值为入度(为什么,因为题目限制了课程号必须在课程总数内)

  3. 构造课程号集合,集合中每个元素同样为子集合,存储着课程号指向的课程号(记录出度指向,也就是指向元素的入度)

  4. 从课程号中取出入度为0的元素,加入队列中,然后根据课程号集合,将指向的课程号子集合中的课程号的入度-1,循环结束(队列为空)

  5. 每取出一个入度为0 的元素,就让课程号总数-1,若循环结束(队列为空),课程号总数==0,说明拓扑排序得到的排序序列 = 课程号总数 说明该有向图不存在环,也就满足题目可以完成全部课程,否则有环,就必然不可能完成

java 复制代码
// 方法一bfs优化:
public boolean canFinish(int numCourses, int[][] prerequisites) {
    
    int[] cous = new int[numCourses];// 构造入度数组 初始化全部位0  长度为课程数

    Queue<Integer> queue = new LinkedList<>();//存放课程号入度为0的元素  入队再出队

    List<List<Integer>> cousList = new ArrayList<>();//构造课程号集合,集合中每个元素同样为子集合,存储着课程号指向的课程号(记录出度指向,也就是指向元素的入度)

    for(int i = 0 ;i < numCourses ; i++) // 提前给课程号集合创建空子集合
      cousList.add(new ArrayList<>());
 
    for(int[] pre : prerequisites){// 给入度数组附上 入度值,以及给课程号集合的子集合设置好出度课程和入度课程的映射
       cous[pre[0]]++;
       cousList.get(pre[1]).add(pre[0]);
    }
    for(int i = 0 ; i<numCourses ; i++){//从课程号数组中取出课程号的入度为0的元素,将课程号加入队列中
      if(cous[i]==0)  queue.offer(i);
    }

    while(!queue.isEmpty()){
        int ids =  queue.poll();//取出队列入度为0的元素
        numCourses--;//取出一个入度为0 的元素  就让课程总数-1
        for(int cur : cousList.get(ids)){// 根据入度为0 的课程号到课程号集合找到 指向的课程号集合,
          if(cous[cur] >= 1) cous[cur]--;// 如果入度大于>=1将集合的课程号入度-1
          if(cous[cur] == 0) queue.offer(cur); //如果入度==0  则将课程号加入到队列
        }
    }

    if(numCourses == 0) return true;//如果numCourses--到了0  说明该课程构成的有向图 无环 满足题目所有课程都能学习
    else return false;//否则不满足
    
  }

方法二:dfs 深度优先搜索

思路:

  1. 将课程号数组,以下标为课程,数值初始化为0
  2. 构建课程号指向的课程号集合
  3. 寻找课程号数组值为0的课程号进行dfs深度优先
  4. 深度优先现将当前课程号设置为1,然后根据课程号指向的课程号集合寻找下一个课程号为0 的课程号继续dfs,dfs后判断标志位是否置为fasle了,如果是,就取反结束dfs,若不是则继续判断课程号数组的值是否为1,是就代表有环,直接返回false,最后都不满足,说明无环,将当前dfs的元素课程号的值置为2
java 复制代码
  List<List<Integer>> cousList;
    int[] cous;
    boolean valid = true;
public boolean canFinish(int numCourses, int[][] prerequisites) {
    
     cous = new int[numCourses];// 构造入度数组 初始化全部位0  长度为课程数

     cousList = new ArrayList<>();//构造课程号集合,集合中每个元素同样为子集合,存储着课程号指向的课程号(记录出度指向,也就是指向元素的入度)

    for(int i = 0 ;i < numCourses ; i++) // 提前给课程号集合创建空子集合
      cousList.add(new ArrayList<>());
 
    for(int[] pre : prerequisites){// 给课程号集合的子集合设置好出度课程和入度课程的映射
       cousList.get(pre[1]).add(pre[0]);
    }

    for(int i = 0 ; i<numCourses ; i++){//
      if(cous[i] == 0)  dfs(i);  //如果是未搜索的科目,则深搜
    }

    return valid;

  }
     
    public void dfs(int c){
        cous[c] = 1;
        for(int cur : cousList.get(c)){//遍历该科目指向的学科
          if(cous[cur]==0){//如果指向的某一学科未搜索过,则深搜
            dfs(cur);
            if(!valid){
              return;
            }
          }else if(cous[cur]==1){//如果指向的某一学科在搜索中,则有环,标记Vaild
                valid = false;
                return;
          }

        }
    cous[c]=2;//因为该科目已经完成深搜,所以标记它的状态搜索完成
  }
相关推荐
文火冰糖的硅基工坊7 分钟前
[人工智能-大模型-103]:模型层 - M个神经元组成的单层神经网络的本质
python·算法·机器学习
m0_7369270419 分钟前
Java面试场景题及答案总结(2025版持续更新)
java·开发语言·后端·职场和发展
无语子yyds34 分钟前
C++双指针算法例题
数据结构·c++·算法
Skrrapper42 分钟前
【STL】set、multiset、unordered_set、unordered_multiset 的区别
c++·算法·哈希算法
SunnyKriSmile1 小时前
函数递归求最大值
c语言·算法·函数递归
傻啦嘿哟1 小时前
爬虫数据去重:BloomFilter算法实现指南
爬虫·算法
立志成为大牛的小牛1 小时前
数据结构——三十六、拓扑排序(王道408)
数据结构·学习·程序人生·考研·算法
绛洞花主敏明3 小时前
Go切片的赋值
c++·算法·golang
10001hours5 小时前
初阶数据结构.1.顺序表.通讯录项目(只有源码和注释)
数据结构·算法
Emilia486.7 小时前
八大排序算法
算法·排序算法