想要精通算法和SQL的成长之路 - 课程表II

news2025/1/18 19:08:47

想要精通算法和SQL的成长之路 - 课程表

  • 前言
  • 一. 课程表II (拓扑排序)
    • 1.1 拓扑排序
    • 1.2 题解

前言

想要精通算法和SQL的成长之路 - 系列导航

一. 课程表II (拓扑排序)

原题链接
在这里插入图片描述

1.1 拓扑排序

核心知识:

  1. 拓扑排序是专门应用于有向图的算法。
  2. BFS的写法就叫拓扑排序,核心就是:让入度为0的节点入队。
  3. 拓扑排序的结果不唯一。
  4. 同时拓扑排序有一个重要的功能:能够检测有向图中是否存在环。

我们先分析一下本题:

  1. 先说下课程,课程有它自己的一个先后的依赖顺序。符合 “有向”
  2. 想要学习某个课程,它的前缀课程可能有多个。那么我们可以用 “度” 的概念去标识衡量。这里是入度。

先用图来解释下本次算法的核心方向(摘自leetcode题解):

  1. 在这里插入图片描述
  2. 在这里插入图片描述
  3. 在这里插入图片描述
  4. 在这里插入图片描述
  5. 在这里插入图片描述
  6. 在这里插入图片描述

说白了就是:

  1. 不断地找入度为0的节点,然后剔除。剔除的同时维护后续节点的入度数
  2. 以此类推。

1.2 题解

那么本题我们该如何解?我们一步步来,我们以numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] 为例来说。官方解释:

  • 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
public int[] findOrder(int numCourses, int[][] prerequisites) {

}

那么我们可以知道这个二维数组prerequisites中,第二个数字代表:”前缀“,第一个数字代表:”后缀“。[1,0] 用图表示就是:0->1同时我们还可以计算出,此时1这个节点的入度应该+1。因为0指向了1。

1.首先,我们要对入参做一个校验:

// 1. 先判断数组或者numCourses为空的情况
if (numCourses <= 0) {
    return new int[0];
}

2.我们需要遍历二维数组prerequisites中,拿到所有节点的入度以及这个拓扑图的结构。

  • 我们用inDegree[]数组表示各个节点的入度。
  • 用一个HashSet数组表示邻接表的结果。数组的索引代表的是节点的值。数组值(即HashMap)代表这个节点的所有后继节点。以0为例,它的后继节点有1和2。
// 2. 用inDegree[] 数组表示每个节点的入度数。
// 同时维护拓扑图的结构例如:0->1,0->2
HashSet<Integer>[] adj = new HashSet[numCourses];
// 初始化下
for (int i = 0; i < numCourses; i++) {
    adj[i] = new HashSet<>();
}
// 构建入度
int[] inDegree = new int[numCourses];
for (int[] p : prerequisites) {
    // 入度+1
    inDegree[p[0]]++;
    // 把当前节点的后继节点存储起来
    adj[p[1]].add(p[0]);
}

3.我们用一个队列,用来存储入度为0的节点。

// 3.准备个队列,存储入度为0的节点
LinkedList<Integer> queue = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
    if (inDegree[i] == 0) {
        queue.offer(i);
    }
}

为啥要这一个步骤?如果发现没有入度为0的节点,说明啥,成环了,那本题就无解。如图:
在这里插入图片描述
4.如果存在入度为0的节点,我们开始往后递归,做2.1节的内容。

  • 先拿到入度为0的节点,删除它(把他放入结果集)。
  • 同时维护后继节点的入度。
  • 如果后继节点入度数-1后,为0。那么同样放入到队列中递归。
// 结果集
int[] res = new int[numCourses];
// 统计结果集中的个数
int count = 0;
while (!queue.isEmpty()) {
    // 入度为0的节点,我们弹出
    Integer head = queue.poll();
    // 放入结果集
    res[count++] = head;
    // 当前入度为0节点对应的后继节点。如果是0 --> 1,2
    HashSet<Integer> nextNodeList = adj[head];
    // 更新后继节点的入度
    for (Integer nextNode : nextNodeList) {
        // 对应的后继节点的入度要减1,
        inDegree[nextNode]--;
        // 如果入度-1后,为0了。再入队
        if (inDegree[nextNode] == 0) {
            queue.offer(nextNode);
        }
    }
}

最后,我们只需要关心结果集个数是否和题干中的numCourses一致。一致的话返回我们构建的结果集,否则本题为空解:

// 如果遍历完了,发现count数量和 numCourses一致,说明有一个正确的结果集
if (count == numCourses) {
    return res;
}
return new int[0];

最终完整代码如下:

public class Test210 {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        // 1. 先判断数组或者numCourses为空的情况
        if (numCourses <= 0) {
            return new int[0];
        }
        // 2. 用inDegree[] 数组表示每个节点的入度数。
        // 同时维护拓扑图的结构例如:0->1,0->2
        HashSet<Integer>[] adj = new HashSet[numCourses];
        // 初始化下
        for (int i = 0; i < numCourses; i++) {
            adj[i] = new HashSet<>();
        }
        // 构建入度
        int[] inDegree = new int[numCourses];
        for (int[] p : prerequisites) {
            // 入度+1
            inDegree[p[0]]++;
            // 把当前节点的后继节点存储起来
            adj[p[1]].add(p[0]);
        }
        // 3.准备个队列,存储入度为0的节点
        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                queue.offer(i);
            }
        }
        // 结果集
        int[] res = new int[numCourses];
        // 统计结果集中的个数
        int count = 0;
        while (!queue.isEmpty()) {
            // 入度为0的节点,我们弹出
            Integer head = queue.poll();
            // 放入结果集
            res[count++] = head;
            // 当前入度为0节点对应的后继节点。如果是0 -- > 1,2
            HashSet<Integer> nextNodeList = adj[head];
            // 更新后继节点的入度
            for (Integer nextNode : nextNodeList) {
                // 对应的next节点的入度要减1,
                inDegree[nextNode]--;
                // 如果入度-1后,为0了。再入队
                if (inDegree[nextNode] == 0) {
                    queue.offer(nextNode);
                }
            }
        }
        // 如果遍历完了,发现count数量和 numCourses一致,说明有一个正确的结果集
        if (count == numCourses) {
            return res;
        }
        return new int[0];
    }
}

这个题目,算是课程表系列的第二道了。第一道:207. 课程表,做法和上面一模一样,只不过返回数组的地方返回true/false即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/997583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sharding-JDBC分库分表-自定义分片算法-4

默认分片算法 Sharding JDBC通过org.apache.shardingsphere.sharding.spi.ShardingAlgorithm接口定义了数据分片算法&#xff0c;5.2.1版本默认提供了如下的分片算法 配置标识自动分片算法详细说明类名MODY基于取模的分片算法ModShardingAlgorithmHASH_MODY基于哈希取模的分片…

JavaFX下载

下载地址&#xff1a; https://gluonhq.com/products/javafx/

postman和node.js的使用

一 nodejs下载 下载链接&#xff1a; nodejs官网&#xff1a; https://nodejs.org/zh-cn/download 我使用的windows .msi安装方式&#xff0c;双击一直下一步就行 当前安装完成后的版本&#xff1a;1.下载 2.安装步骤 下载完成后&#xff0c;双击安装包&#xff0c;开始安装&…

在MAC电脑上将NTFS格式移动硬盘转换为ExFAT格式

注意&#xff1a;转化之前先将移动硬盘中的内容进行备份 1、点击桌面上的【前往】&#xff0c;选择【实用工具】 2、在列表中选择【磁盘工具】 3、在左侧选中你的磁盘&#xff0c;点击右侧上方的【抹掉】,注意&#xff1a;将永久抹掉储存在上面的所有数据&#xff0c;因此需要…

计算机毕业设计 JSPM校园闲置物品交易平台的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

分类预测 | Matlab实现基于LFDA-SVM局部费歇尔判别数据降维结合支持向量机的多输入分类预测

分类预测 | Matlab实现基于LFDA-SVM局部费歇尔判别数据降维结合支持向量机的多输入分类预测 目录 分类预测 | Matlab实现基于LFDA-SVM局部费歇尔判别数据降维结合支持向量机的多输入分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于局部费歇尔判别数据降维的L…

Ubuntu下高效Vim的搭建(离线版)

软件界面 可以看到界面下方有一些常用提示信息&#xff1a;文件路径、format、文件类型、光标所在的坐标(x,y)、进度条(百分比)、日期时间 会提示已定义的变量名词(快速补全) 搭建方法 下载资源文件 把Vim 和 .vimrc 拷贝到家目录下&#xff0c;并执行tar -xvf Vim 即可。 …

汇川PLC学习Day3:轴控代码编写、用户程序结构说明与任务配置示例、用户变量空间与编址

汇川PLC学习Day3&#xff1a;轴控代码编写、用户程序结构说明与任务配置示例、用户变量空间与编址 一、新建轴与轴控代码编写 1. 新建轴 (1)新建一个轴 &#xff08;2&#xff09;将轴名字更新为实际名字 可以后面实例化后再更改&#xff0c;汇川可以在更新名字时同步更新…

使用DeepSpeed加速大型模型训练(二)

使用DeepSpeed加速大型模型训练 在这篇文章中&#xff0c;我们将了解如何利用Accelerate库来训练大型模型&#xff0c;从而使用户能够利用DeeSpeed的 ZeRO 功能。 简介 尝试训练大型模型时是否厌倦了内存不足 (OOM) 错误&#xff1f;我们已经为您提供了保障。大型模型性能非…

倒⽴摆闭环控制的设计与开发

倒立摆是一种典型的多变量、高阶次、非线性、强耦合、自然不稳定系统&#xff0c;常被用来检验新的控制理论和算法的正确性及其在实际应用中的有效性。 load func_ip_comp% Locations of Poles and Zeroes of Open-Loop Compensated Transfer Function in Complex Plane figur…

查看当前所有的数据库

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 先看下服务有没有启动,看下我这个是什么意思 exit 退出MySQL环境回车后是这样的 重新进入MySQL环境 查看当前所有的数据库 show datebases; mysql&…

nrf523832 串口点LED

/* P0.06&#xff1a;串口发送TXD P0.08&#xff1a;串口接收RXD P0.05&#xff1a;串口RTS&#xff1a;发送请求&#xff0c;硬件流控开启时有效 P0.07&#xff1a;串口CTS&#xff1a;发送允许&#xff0c;硬件流控开启时有效 */ #define RX_PIN_NUMBER 8 #define TX_PIN_N…

学习Bootstrap 5的第十天

目录 卡片 基础的卡片 实例 页眉和页脚 实例 多种颜色卡片 实例 标题、文本和链接 实例 图片卡片 实例 卡片图像叠加 实例 下拉菜单 基础的下拉列表 实例 下拉列表分隔线 实例 下拉列表标题 实例 禁用的和活动的项目 实例 下拉列表位置 实例 下拉菜单…

SpringMVC之文件的上传下载(教你如何使用有关SpringMVC知识实现文件上传下载的超详细博客)

目录 前言 一、文件上传 1. 配置多功能视图解析器&#xff08;spring-mvc.xml&#xff09; 2. 添加文件上传页面&#xff08;upload.jsp&#xff09; upload.jsp 3.做硬盘网络路径映射 4. 编写一个处理页面跳转的类 PageController.java ClazzController.java 5. 初步模…

【数据分享】STRM 90米分辨率DEM地形数据(无需转发/全国/分省/分市)

地形数据是我们在各种设计、研究中都经常使用的基础数据&#xff01;之前我们分享过12.5米精度的DEM地形数据、30米精度的DEM地形数据(均可查看之前的文章获悉详情&#xff09;。 本次给大家带来的是90米分辨率的DEM地形数据——STRM 90m高程数据&#xff01;该数据是由美国太…

学成在线-网站搭建

文章目录 代码素材来自b站pink老师 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>学成在线首…

《PWA实战:如何为你的网站增加离线功能和推送通知》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Hbase解决ERROR: KeeperErrorCode = ConnectionLoss for /hbase/master报错

1、在单机模式中&#xff0c;要先修改一个文件&#xff1a;/usr/local/hbase/conf/hbase-site.xml hbase-site.xml内容&#xff1a; <configuration><property><name>hbase.rootdir</name><value>file:///usr/local/hbase/hbase-tmp</value…

dji uav建图导航系列()move_base

文章目录 1、导航框架2、move_base功能包3、amcl功能包4、代价地图的配置4.1、通用配置文件4.2、全局规划配置文件4.3、局部规划配置文件5、局部规划器配置6、launch文件1、导航框架 导航的关键是机器人定位和路径规划两大部分 move_base:实现机器人导航中的最优路径规划 am…

ES8生产实践——pod日志采集(Elastic Agent方案)

pod日志采集方案 方案选型 DaemonSetElastic Agent方案&#xff1a;使用DaemonSet控制器在每个kubernetes集群节点上运行elastic agent服务&#xff0c;业务容器日志目录统一挂载到节点指定目录下。在fleet中配置集成Custom Logs集成策略&#xff0c;指定日志采集目录和inges…