LeetCode 热题 100_课程表(53_207_中等_C++)(图,拓扑排序)

LeetCode 热题 100_课程表(53_207)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 思路一(广度优先搜索+拓扑排序):
      • 代码实现
        • 代码实现(思路一(拓扑排序)):
        • 以思路一为例进行调试

题目描述:

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

示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同

题解:

解题思路:

思路一(广度优先搜索+拓扑排序):

1、本题的要求是在选修某些课程之前需要一些先修课程,且两个课程不能互为先修课程。例子(false):学课程 ai 之前必学 bi,且学课程 bi 之前必学 ai,是不能进行下去的。通过问题的分析,我们发现此问题就是判断当前课程的学习是否构成一个环(有向图),判断环的存在,我们可以使用拓扑排序。在进行拓扑排序后,如果还存在入度为0结点则返回false,否则返回true。

2、具体思路如下:
① 在进行拓扑排序的时候我们需要从入度为0的结点开始,这样我们就要事先统计入度为0的结点,将这些结点加入队列中。
② 将队首结点出队,将此节点后继结点的入度减去(为了方便找到此节点的后继结点我们可以存储此节点和其后继结点的对应关系:邻接表)。



③ 重复上述过程直至队空为止,若此时存在入度>0的结点则返回false,否则返回true(我们也可以统计入度为0结点的数量,最后与总的结点数进行比较,相同则返回true,否则返回false)。

3、复杂度分析:
① 时间复杂度:O(n+m),其中 n 为课程数,m 为先修课程的要求数。首先遍历一遍所有的先修课程,统计每个课程的入度并统计每个课程的后继课程O(m)。将入度为0的课程压入栈中O(n),拓扑排序遍历课程结点O(n)。

② 空间复杂度:O(n+m),其中 n 为课程数,m 为先修课程的要求数。存储每个课程的入度O(n)和存储每个课程的后继课程(邻接表)O(n+m)(m可以理解为图中的边数)。

代码实现

代码实现(思路一(拓扑排序)):
class Solution {
private:
    //in_degree存储每个结点的入度(下标代表当前结点)
    vector<int> in_degree;
    //存储每个结点对应的后继结点:邻接表(下标代表当前结点,与之对应的vector<int>为对应的出边)
    vector<vector<int>> thisNode_successors;

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //Q队列用于存储入度为0的结点
        queue<int> Q;
        int n=0;
        
        //重置数组的大小,并将入度初始化为0
        thisNode_successors.resize(numCourses);
        in_degree.resize(numCourses,0);

        //统计每个课程的入度并统计每个课程的后继课程
        for (const auto & prerequisite : prerequisites)
        {
            //统计每个课程的入度
            in_degree[prerequisite[0]]++; 
            
            //统计每个课程的后继课程
            thisNode_successors[prerequisite[1]].push_back(prerequisite[0]);
        }
        
        //将一开始入度为0的结点入队,并统计入度为0的结点数
        for (int i = 0; i < numCourses; i++){
            if (in_degree[i]==0) Q.push(i);
            ++n;
        }
            

        //将队首结点出队,将此节点后继结点的入度减去,将剩余入度为0的结点入队,并统计入度为0的结点数
        while (!Q.empty())
        {
            //将队首结点出队
            int currentNode= Q.front();
            Q.pop();
            //将此节点后继结点的入度减去,将剩余入度为0的结点入队,并统计入度为0的结点数
            for (auto &successor : thisNode_successors[currentNode])
            {
                in_degree[successor]--;
                if (in_degree[successor]==0)
                {
                    Q.push(successor);
                    ++n;
                } 
            } 
        }

        //将入度为0的结点与总的结点数进行比较,相同则返回true,否则返回false
        if(n==numCourses) return true;
        return false;
    }
};
以思路一为例进行调试
#include<iostream>
#include <vector>
#include <queue>
using namespace std;

class Solution {
private:
    //in_degree存储每个结点的入度(下标代表当前结点)
    vector<int> in_degree;
    //存储每个结点对应的后继结点:邻接表(下标代表当前结点,与之对应的vector<int>为对应的出边)
    vector<vector<int>> thisNode_successors;

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //Q队列用于存储入度为0的结点
        queue<int> Q;
        int n=0;
        
        //重置数组的大小,并将入度初始化为0
        thisNode_successors.resize(numCourses);
        in_degree.resize(numCourses,0);

        //统计每个课程的入度并统计每个课程的后继课程
        for (const auto & prerequisite : prerequisites)
        {
            //统计每个课程的入度
            in_degree[prerequisite[0]]++; 
            
            //统计每个课程的后继课程
            thisNode_successors[prerequisite[1]].push_back(prerequisite[0]);
        }
        
        //将一开始入度为0的结点入队,并统计入度为0的结点数
        for (int i = 0; i < numCourses; i++){
            if (in_degree[i]==0) Q.push(i);
            ++n;
        }

        //将队首结点出队,将此节点后继结点的入度减去,将剩余入度为0的结点入队,并统计入度为0的结点数
        while (!Q.empty())
        {
            //将队首结点出队
            int currentNode= Q.front();
            Q.pop();
            //将此节点后继结点的入度减去,将剩余入度为0的结点入队,并统计入度为0的结点数
            for (auto &successor : thisNode_successors[currentNode])
            {
                in_degree[successor]--;
                if (in_degree[successor]==0)
                {
                    Q.push(successor);
                    ++n;
                } 
            } 
        }

        //将入度为0的结点与总的结点数进行比较,相同则返回true,否则返回false
        if(n==numCourses) return true;
        return false;
    }
};

int main(int argc, char const *argv[])
{
    //总共有 2 门课程
    int numCourses=2;
    //两门课程的对应关系
    vector<vector<int>> prerequisites={{1,0},{0,1}};
    
    Solution s;
    if(s.canFinish(numCourses,prerequisites)){
        cout<<"true";
    }else{
        cout<<"false";
    }
    return 0;
}

LeetCode 热题 100_课程表(53_207)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

sparkSQL练习

1.前期准备 &#xff08;1&#xff09;建议先把这两篇文章都看一下吧&#xff0c;然后把这个项目也搞下来 &#xff08;2&#xff09;看看这个任务 &#xff08;3&#xff09;score.txt student_id,course_code,score 108,3-105,99 105,3-105,88 107,3-105,77 105,3-245,87 1…

GIFT ICA 下载记录

1.帮助文档 Group ICA/IVA Of fMRI Toolbox&#xff1b;【GIFT介绍】 Group ICA of fMRI Toolbox (GIFT) Walk Through&#xff1b;【流程介绍】 GIFT v1.3c Functions Srinivas Rachakonda, Eric Egolf and Vince Calhoun【流程解释】 2.下载记录 从官网下载程序包&#xff0…

从零深度学习:(2)最小二乘法

今天我们从比较简单的线性回归开始讲起&#xff0c;还是一样我们先导入包 import numpy as np import torch import matplotlib as mpl import matplotlib.pyplot as plt a torch.arange(1,5).reshape(2,2).float() a 我们利用刚刚导入的画图的包将这两个点画出来&#xff0…

02JavaWeb——JavaScript-Vue(项目实战)

一、JavaScript html完成了架子&#xff0c;css做了美化&#xff0c;但是网页是死的&#xff0c;我们需要给他注入灵魂&#xff0c;所以接下来我们需要学习 JavaScript&#xff0c;这门语言会让我们的页面能够和用户进行交互。 1.1 介绍 通过JS/js效果演示提供资料进行效果演…

【Flink系列】5. DataStream API

5. DataStream API DataStream API是Flink的核心层API。一个Flink程序&#xff0c;其实就是对DataStream的各种转换。具体来说&#xff0c;代码基本上都由以下几部分构成&#xff1a; 5.1 执行环境&#xff08;Execution Environment&#xff09; Flink程序可以在各种上下文…

大模型高并发部署方案探究

版本 内容 姓名 时间 V1.0 新建 xx 2025-01-16 声明&#xff1a;只是进行探究&#xff0c;后续真正实践后&#xff0c;会更新新的内容 前置条件&#xff1a;70B的模型&#xff0c;并发要求200 性能测试参考链接 Benchmarking LLM Inference Backends :表明一台A100(8…

MIAOYUN信创云原生项目亮相西部“中试”生态对接活动

近日&#xff0c;以“构建‘中试’生态&#xff0c;赋能科技成果转化”为主题的“科创天府智汇蓉城”西部“中试”生态对接活动在成都高新区菁蓉汇隆重开幕。活动分为成果展览、“中试”生态主场以及成果路演洽谈对接三大板块。在成果展览环节&#xff0c;成都元来云志科技有限…

pytest-instafail:让测试失败信息即时反馈

pytest-instafail&#xff1a;让测试失败信息即时反馈 前言一、简介二、优势三、安装与使用3.1 未安装时运行情况3.2 安装3.3 已安装时运行情况3.3 pytest.ini 配置选项 四、对比 总结 前言 当测试用例数量庞大时&#xff0c;定位测试失败的原因往往耗时费力。此时&#xff0c;…

低代码平台:技术复杂性的系统简化

在传统开发模式下&#xff0c;应用构建需要经历需求分析、代码开发、测试部署等多环节&#xff0c;流程繁琐且耗时&#xff0c;往往成为企业技术创新的瓶颈。低代码平台通过模块化和自动化技术重新定义开发流程&#xff0c;使开发者能够在较短时间内实现复杂的应用功能&#xf…

精度论文:【Focaler-IoU: More Focused Intersection over Union Loss】

Focaler-IoU: 更聚焦的交并比损失 Focaler-IoU: More Focused Intersection over Union Loss Focaler-IoU: 更聚焦的交并比损失I. 引言II. 相关工作III. 方法IV. 实验V. 结论 原文地址&#xff1a;官方论文地址 代码地址&#xff1a;官方代码地址 摘要——边界框回归在目标检…

“AI智慧化服务系统:未来生活的智能管家

在当今快速发展的科技时代&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的速度改变着我们的生活。AI智慧化服务系统作为这一变革的前沿技术&#xff0c;正在逐渐成为我们未来生活的智能管家。它们不仅提高了服务效率&#xff0c;还为我们带来了更加个性化和便捷…

nginx 修改内置 404 页面、点击劫持攻击。

1、在部署前端项目的目录下增加 404.html 页面&#xff1a;/opt/web/404.html。 2、在 nginx 配置中增加 404 配置&#xff1a; root /opt/web; # 设置根目录的配置error_page 404 404.html; location /404.html {root /opt/web;# 指定 404 页面所在的根目录internal;# 确保…

网络密集型应用的Linux网络缓冲区参数优化

一、网络IO密集型 1.哪些应用属于网络IO密集型应用 文件上传、下载服务器&#xff0c;实时大数据同步复制&#xff0c;Kafka巨量数据QPS生产消费环境&#xff0c;CDN等环境都是网络IO密集型的服务应用 2.知识来源 在《kafka权威指南2》书中环境搭建的网络小节写到了几个参数…

npm发布组件(vue3+webpack)

1.初始化Vue项目 vue create my-app 2.本地运行 npm run serve 3.新增目录和文件 1. src/package/index.js 2. src/package/wlz-btn/index.vue 3. src/package/wlz-input/index.vue // src\package\index.js import WlzBtn from "./wlz-btn"; import WlzInput …

Day05-后端Web基础——TomcatServletHTTP协议SpringBootWeb入门

目录 Web基础知识课程内容1. Tomcat1.1 简介1.2 基本使用1.2.1 下载1.2.2 安装与卸载1.2.3 启动与关闭1.2.4 常见问题 2. Servlet2.1 快速入门2.1.1 什么是Servlet2.1.2 入门程序2.1.3 注意事项 2.2 执行流程 3. HTTP协议3.1 HTTP-概述3.1.1 介绍3.1.2 特点 3.2 HTTP-请求协议3…

两级式三相光伏并网逆变器Matlab/Simulink仿真模型

忘记更新最经典的光伏并网仿真模型了&#xff0c;作为包含经典的MPPT和并网恒功率因素的双闭环控制模型&#xff0c;也是很多相关专业学生的入门研究内容&#xff0c;光伏并网模型三相的和单相都有。 其中三相光伏并网逆变器有大功率和小功率的两种&#xff0c;之前早在硕士期…

将图像输入批次扁平化为CNN

将图像输入批次扁平化为CNN 欢迎回到这个神经网络编程系列。在这篇文章中&#xff0c;我们将可视化一个单一灰度图像的张量扁平化操作&#xff0c;并且我们将展示如何扁平化特定的张量轴&#xff0c;这在使用CNN时通常是必需的&#xff0c;因为我们处理的是输入批次&#xff0…

Linux命令行工具-使用方法

参考资料 Linux网络命令&#xff1a;网络工具socat详解-CSDN博客 arm-linux-gnueabihf、aarch64-linux-gnu等ARM交叉编译GCC的区别_aarch64-elf-gcc aarch64-linux-gnu-CSDN博客 解决Linux内核问题实用技巧之-dev/mem的新玩法-腾讯云开发者社区-腾讯云 热爱学习地派大星-CS…

浅谈云计算20 | OpenStack管理模块(下)

OpenStack管理模块&#xff08;下&#xff09; 五、存储管理5.1 存储管理概述 5.2 架构设计5.2.1 Cinder块存储架构5.2.2 Swift对象存储架构 六、网络管理6.1 网络管理概述6.2 架构解析6.2.1 Neutron网络服务架构6.2.2 网络拓扑架构 6.3 原理与流程6.3.1 网络创建原理6.3.2 网络…

GPU 硬件原理架构(一)

这张费米管线架构图能看懂了&#xff0c;整个GPU的架构基本就熟了。市面上有很多GPU厂家&#xff0c;他们产品的架构各不相同&#xff0c;但是核心往往差不多&#xff0c;整明白一了个基本上就可以触类旁通了。下面这张图信息量很大&#xff0c;可以结合博客GPU 英伟达GPU架构回…