【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;//因为该科目已经完成深搜,所以标记它的状态搜索完成
  }
相关推荐
CoderYanger7 分钟前
递归、搜索与回溯-综合练习:27.黄金矿工
java·算法·leetcode·深度优先·1024程序员节
zs宝来了9 分钟前
HOT100系列-堆类型题
数据结构·算法·排序算法
Christo322 分钟前
ICML-2019《Optimal Transport for structured data with application on graphs》
人工智能·算法·机器学习·数据挖掘
sin_hielo25 分钟前
leetcode 1590
数据结构·算法·leetcode
吃着火锅x唱着歌27 分钟前
LeetCode 2748.美丽下标对的数目
数据结构·算法·leetcode
做怪小疯子28 分钟前
LeetCode 热题 100——二叉树——二叉树的中序遍历
算法·leetcode·职场和发展
一只乔哇噻35 分钟前
java后端工程师+AI大模型进修ing(研一版‖day57)
java·开发语言·人工智能·算法·语言模型
软件测试雪儿37 分钟前
2025年100道最新软件测试面试题,常见面试题及答案汇总
软件测试·测试工具·职场和发展
晨曦夜月1 小时前
笔试强训day4
算法
自然语1 小时前
人工智能之数字生命-学习的过程
数据结构·人工智能·深度学习·学习·算法