【力扣hot100】207 课程表(c++、python)解析

相关题目: 210 课程表2

【力扣hot100】207 课程表(c++、python)解析

  • 1.官方题解:
    • 1.1深搜
      • c++版本
      • python版本
    • 1.2广搜
      • c++版本

1.官方题解:

这是一题经典的「拓扑排序」问题

给定一个包含 n 个节点的有向图 G,我们给出它的节点编号的一种排列,如果满足:对于图 G 中的任意一条有向边 (u,v),u 在排列中都出现在 v 的前面那么称该排列是图 G 的「拓扑排序」

*1.如果图 G 中存在环(即图 G 不是「有向无环图」),那么图 G 不存在拓扑排序。这是因为假设图中存在环 “x1,x2,…,„,í,那么 x1在排列中必须出现在 xn 的前面,但 xn同时也必须出现在 x1的前面,因此不存在一个满足要求的排列,也就不存在拓扑排序

*2.如果图 G 是有向无环图,那么它的拓扑排序可能不止一种。举一个最极端的例子,如果图 G 值包含n个节点却没有任何边,那么任意一种编号的排列都可以作为拓扑排序

有了上述的简单分析,我们就可以将本题建模成一个求拓扑排序的问题了

我们将每一门课看成一个节点
如果想要学习课程 A 之前必须完成课程 B,那么我们从 B 到 A 连接一条有向边。这样以来,在拓扑排序中,B一定出现在 A 的前面。

在这里插入图片描述

在这里插入图片描述

1.1深搜

从出度思考(从后往前排序), 出度为0的节点在拓扑排序中一定排在后面, 然后删除和该节点对应的边, 迭代寻找出度为0的节点

我们可以将深度优先搜索的流程与拓扑排序的求解联系起来,用一个栈来存储所有已经搜索完成的节点。

对于一个节点 u,如果它的所有相邻节点都已经搜索完成,那么在搜索回溯到u的时候,u本身也会变成一个已经搜索完成的节点。这里的「相邻节点」指的是从u出发通过一条有向边可以到达的所有节点。

假设我们当前搜索到了节点u,如果它的所有相邻节点都已经搜索完成,那么这些节点都已经在栈中了,此时我们就可以把u入栈。可以发现,如果我们从栈顶往栈底的顺序看,由于 u 处于栈顶的位置,那么 u 出现在所有 u 的相邻节点的前面。因此对于 u 这个节点而言,它是满足拓扑排序的要求的。

这样以来,我们对图进行一遍深度优先搜索。当每个节点进行回溯的时候,我们把该节点放入栈中。最终从栈顶到栈底的序列就是一种拓扑排序。
在这里插入图片描述
在这里插入图片描述

c++版本

//一个二维向量,用于表示课程之间的依赖关系,每个元素`edges[u]`表示依赖先修课程`u`的课程。
//`visited`:用于标记课程的访问状态,0表示未访问,1表示正在访问,2表示已访问。
//`valid`:表示当前的课程安排是否有效,初始值为`true`
class Solution{
private:vector<vector<int>> edges; vector<int> visited;bool valid = true;public:
//用于从课程`u`开始进行深度优先遍历。在遍历过程中,会对课程进行标记,同时检查是否存在环路。若存在环路,则将`valid`设为`false`,表示无法完成所有课程。void dfs(int u) {visited[u] = 1;//从课程`u`开始进行深度优先遍历for(int v:edges[u])//遍历课程u的先修课程{if(visited[v] == 0)//如果有没访问的先修课程{dfs(v);//dfsif(!valid){return;}}else if(visited[v] ==1)//出现环路{valid = false;//直接置为falsereturn;}}visited[u] =2;//u这个课程 已访问结束}bool canFinish(int numCourses, vector<vector<int>>& prerequisites)//函数实现{//根据输入的先修课程信息,构建课程之间的依赖关系edges.resize(numCourses);visited.resize(numCourses);for (const auto& info:prerequisites){edges[info[1]].push_back(info[0]);
//举个例子,在 prerequisites 列表中有一个元素 [1, 0],意味着课程 1 的先修课程是课程 0。那么在 edges 字典中,edges[0] 
//就是存储了依赖于课程 0 的所有课程的列表。而在这一行代码中,就将课程 1 的编号添加到了 edges[0] 对应的列表中,表示课程 1 依赖于课程 0}for(int i = 0; i<numCourses &&valid; ++i){if(!visited[i]){dfs(i);}}return valid;}
};

python版本

class Solution:#它接受两个参数:`numCourses`表示课程总数,`prerequisites`是一个二维列表,表示课程之间的先修关系。函数返回一个布尔值,表示是否能够完成所有课程def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:edges = collections.defaultdict(list) #导入Python的collections模块,用于创建默认字典使得在后续添加元素时不需要手动创建空列表。visited = [0] * numCourses #创建了一个长度为`numCourses`的列表`visited`用于标记课程的访问状态,初始值都为0。result = list()#创建一个空列表`result`,用于存储访问过的课程的结果valid = True #表示当前的课程安排是否有效,默认为True。#将课程之间的依赖关系添加到`edges`中for info in prerequisites:edges[info[1]].append(info[0])#表示先修课程info[1] 是 现在课程info[0] 的先修课程,把现在的课程添加到先修课程的edges中def dfs(u:int):#在函数内部使用`nonlocal valid`来声明`valid`变量为非局部变量,以便在内部函数中修改外部函数的变量nonlocal validvisited[u] = 1#首先标记当前课程为已访问状态(1),然后对当前课程的所有依赖课程进行遍历for v in edges[u]:if visited[v] == 0:dfs(v)#如果依赖课程未被访问过,则递归调用`dfs`函数if not valid:returnelif visited[v] == 1:# 如果依赖课程正在被访问中(标记为1),表示存在环路,将`valid`设为False,并直接返回valid = Falsereturnvisited[u] = 2result.append(u)#遍历完所有依赖课程后,将当前课程标记为已完成状态(2),并将其添加到结果列表中for i in range(numCourses):if valid and not visited[i]:dfs(i)return valid    

1.2广搜

先学C1, 为0直接加入队列中
在这里插入图片描述
C3和C8都包含C1的入度,-1,C8加入队列中(学完一门课后更新入度,为0加入队列)
在这里插入图片描述
有向有环图无法执行
在这里插入图片描述
在这里插入图片描述
方法一的深度优先搜索是一种「逆向思维」:最先被放入栈中的节点是在拓扑排序中最后面的节点。我们也可以使用正向思维,顺序地生成拓扑排序,这种方法也更加直观。

我们考虑拓扑排序中最前面的节点,该节点一定不会有任何入边,也就是它没有任何的先修课程要求。当我们将一个节点加入答案中后,我们就可以移除它的所有出边,代表着它的相邻节点少了一门先修课程的要求。

如果某个相邻节点变成了「没有任何入边的节点」,那么就代表着这门课可以开始学习了。按照这样的流程,我们不断地将没有入边的节点加入答案,,直到答案中包含所有的节点(得到了一种拓扑排序)或者不存在没有入边的节点(图中包含环)

上面的想法类似于广度优先搜索,因此我们可以将广度优先搜索的流程与拓扑排序的求解联系起来。

c++版本

//广搜
class Solution{private:vector<vector<int>> edges; //这个列表存储了依赖于当前课程的先修课程的所有课程的编号vector<int> indeg; //一个一维向量,用于表示课程的入度(即指向该课程的边的数量)public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites){edges.resize(numCourses);indeg.resize(numCourses);for(const auto & info:prerequisites){//根据输入的先修课程信息,构建课程之间的依赖关系,并更新课程的入度edges[info[1]].push_back(info[0]); //这个列表存储了依赖于当前课程的先修课程info[1]的所有课程info[0]的编号++indeg[info[0]];//增加现在课程的入度}queue<int> q;//队列qfor(int i = 0;i<numCourses;++i){if(indeg[i] == 0)//如果入度为0{q.push(i);//直接push到队列中}}int visited = 0;while (!q.empty()){++visited;int u = q.front();q.pop();for(int v:edges[u]){--indeg[v];if(indeg[v] == 0){q.push(v);}}}return visited == numCourses;}
};

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

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

相关文章

网络七层模型:理解网络通信的架构(〇)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

idea-创建java8的springboot项目

现在使用IDEA创建 Spring Boot 项目&#xff0c;jdk 版本最低要求为 17。Spring Boot 官方在全力维护 3.x 版本&#xff0c;而 Spring Boot 3.x 对 jdk 版本的最低要求为17。 如果需要继续使用 jdk8&#xff0c;则需要修改 Server URL &#xff0c;改成&#xff1a;https://st…

解决 vue activited 无效问题

当对页面APP.vue组件router-view标签使用了keep-alive之后在组件activated状态时不会发送请求&#xff0c;这时需要使用 keep-alive标签的 exclude属性排除需要重新发送请求的组件。需要注意exclude的值要和组件本身的name值要一致&#xff0c;如果不一致就会不生效。目前我出现…

C++运算符重载中的引用返回

文章目录 引言原因1.为了支持链式调用2.避免不必要的对象创建和复制3.保持语义一致性 引言 在C编程语言中&#xff0c;运算符重载是一项强大的特性&#xff0c;它允许程序员为自定义类型重新定义或重载已有的运算符&#xff0c;从而使得这些类型能够像内置类型一样使用运算符。…

离线linux服务器安装mysql8

本文的服务器环境&#xff1a;openEuler毛坯版的&#xff0c;很多常用的指令都没有预装&#xff0c;比如rpm、tar等等&#xff0c;没有网络坏境&#xff0c;需要自己手动配置本地yum仓库&#xff0c;安装相关指令 1、检查服务器是否已经安装了MySQL 1.1、查询mysql以安装的相关…

使用Docker本地搭建蚂蚁笔记并实现无公网IP远程访问

文章目录 1. 安装Docker2. Docker本地部署Leanote蚂蚁笔记3. 安装cpolar内网穿透4. 固定Leanote蚂蚁笔记公网地址 本篇文章介绍如何使用Docker部署Leanote蚂蚁笔记&#xff0c;并且结合cpolar内网穿透实现公网远程访问本地笔记编辑并制作个人博客等。 Leanote 蚂蚁笔记是一款云…

Echarts 仪表盘

1、效果图 2、代码 createTenantChartOne(){var myChart1 this.$echarts.init(document.getElementById(tenant-chart-1));var dataArr 82;var title 仪表盘;let option {graphic: {type: text,left: center,top: 85%,style: {text: title,textAlign: center,//居中对齐fi…

微服务高级篇(五):可靠消息服务

文章目录 一、消息队列MQ存在的问题&#xff1f;二、如何保证 消息可靠性 &#xff1f;2.1 生产者消息确认【对生产者配置】2.2 消息持久化2.3 消费者消息确认【对消费者配置】2.4 消费失败重试机制2.5 消费者失败消息处理策略2.6 总结 三、处理延迟消息&#xff1f;死信交换机…

application.properties 里面和 application.yml 里面都配置了同样的参数 ,哪个会生效

在Spring Boot中&#xff0c;如果application.properties和application.yml&#xff0c;application-dev.yml&#xff08;application.yml中指定了avtive: dev&#xff09;中同时配置了相同的参数&#xff0c;Spring Boot默认会按照一定的加载顺序加载配置文件&#xff0c;并且…

【保姆级带你了解机器学习的概念,步骤,分类和实践】

&#x1f525;博主&#xff1a;程序员不想YY啊&#x1f525; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 &#x1f91d;希望本文对您有所裨益&#xff0c;如有…

方案功能开发:智能机器人玩具

玩具电动趣萌机器人方案开发定制&#xff0c;东莞市酷得智能科技有限公司是研发型芯片贸易公司&#xff0c;可为制造厂商朋友定制软件底层方案。下面介绍一下机器人方案可实现的功能&#xff1a; 基础功能&#xff1a; 方向&#xff1a;前进&#xff0c;后退&#xff0c;左转&a…

springboot项目中如何实现邮件告警功能(监控平台服务模拟)

介绍 模拟服务器故障&#xff0c;然后实现邮件告警 一、首先配置邮件的maven依赖 代码如下&#xff1a; <!--邮件告警--><!-- Spring Boot的邮件发送依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spri…

【嵌入式——QT】多语言界面

【嵌入式——QT】多语言界面 多语言页面开发步骤tr()函数 多语言页面开发步骤 第一步 在你编写的代码中添加tr()函数&#xff0c;方便之后可以精准的定位到你所需要翻译的部分。 第二步 在.pro文件中添加以下代码&#xff0c;这样会让你生成相应的.ts文件&#xff0c;ts文件是…

深度学习Top10算法之深度神经网络DNN

深度神经网络&#xff08;Deep Neural Networks&#xff0c;DNN&#xff09;是人工神经网络&#xff08;Artificial Neural Networks&#xff0c;ANN&#xff09;的一种扩展。它们通过模仿人脑的工作原理来处理数据和创建模式&#xff0c;广泛应用于图像识别、语音识别、自然语…

安捷伦Agilent 85033E机械校准套件

181/2461/8938产品概述&#xff1a; 网络分析中的测量误差可分为两类:随机误差和系统误差。随机误差和系统误差都是矢量。随机误差是不可重复的测量变化&#xff0c;通常是不可预测的。系统误差是测试设置中可重复的测量变化。 系统误差包括阻抗不匹配、系统频率响应和测试设…

javaSwing超级玛丽游戏

一、摘要 摘要 近年来&#xff0c;Java作为一种新的编程语言&#xff0c;以其简单性、可移植性和平台无关性等优点&#xff0c;得到了广泛地应用。J2SE称为Java标准版或Java标准平台。J2SE提供了标准的SDK开发平台。利用该平台可以开发Java桌面应用程序和低端的服务器应用程序…

人工智能聊天机器人与大型语言模型 (LLM):哪个适合您的业务?

简介&#xff1a;欢迎来到未来 您可能听说过人工智能聊天机器人和大型语言模型 (LLM)&#xff0c;对吧&#xff1f; 这些技术奇迹正在重塑企业的沟通和运营方式。 但是&#xff0c;这是一个价值百万美元的问题&#xff1a;哪一个适合您的业务&#xff1f; 让我们深入了解一下&…

【C++航海王:追寻罗杰的编程之路】queue

目录 1 -> queue的介绍和使用 1.1 -> queue的介绍 1.2 -> queue的使用 1.3 -> queue的模拟实现 1 -> queue的介绍和使用 1.1 -> queue的介绍 queue的文档介绍 1. 队列是一种容器适配器&#xff0c;专门用于在FIFO(先进先出)上下文中操作&#xff0c;其…

力扣刷题31-33(力扣 0024/0070/0053)

今日题目&#xff1a; 24. 两两交换链表中的节点 题目&#xff1a;给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09; 思路&…

Linux离线安装Docker-Oracle_11g

拉取oracle11g镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g创建11g容器 docker run -d -p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g查看容器是否创建成功 docker ps -a导出oracle容器&#xff0c;查看…