LeetCodehot 力扣热题100 课程表

news2025/2/24 18:23:50

题目背景

这个问题要求我们判断是否可以完成所有课程的学习。每门课程可能依赖其他课程作为前置课程,构成了一个有向图。我们需要确定是否存在环,若存在环,说明课程之间互相依赖,无法完成所有课程;如果不存在环,则说明可以完成所有课程。

思路解析

1. 图的构建

我们将课程之间的依赖关系视为一个有向图:

• 课程是图的节点。

• 前置课程之间的依赖关系是有向边。例如,如果课程 A 需要课程 B,则我们在图中添加一条从 B 到 A 的边。

2. DFS 检测环

要检查图中是否存在环,经典的方法是使用 深度优先搜索(DFS)

正在访问的节点(颜色为 1:表示该节点正在递归访问中,遇到这种节点意味着图中有环。

已访问的节点(颜色为 2:表示该节点及其所有后续节点已经被访问过,且没有发现环。

未访问的节点(颜色为 0:表示该节点尚未访问。

DFS 的步骤:

• 遍历每个课程,如果课程未访问过,就进行 DFS 检查。

• 如果在 DFS 过程中,发现已经有课程正在访问(即发现环),则返回 false。

• 如果所有课程都能够成功访问且没有发现环,返回 true。

3. 终止条件

• 如果 DFS 中发现环,直接返回 false,说明存在循环依赖。

• 如果 DFS 完成后没有发现环,则返回 true,说明可以完成所有课程。

具体运行步骤

假设有以下示例输入:

int numCourses = 4;

vector<vector<int>> prerequisites = {{1, 0}, {2, 1}, {3, 2}};

这表示有 4 门课程,依赖关系如下:

• 课程 1 依赖课程 0

• 课程 2 依赖课程 1

• 课程 3 依赖课程 2

步骤 1:图的构建

首先,我们构建一个图,表示课程的依赖关系:

• g[0] = [1]:课程 0 依赖课程 1

• g[1] = [2]:课程 1 依赖课程 2

• g[2] = [3]:课程 2 依赖课程 3

• g[3] = []:课程 3 没有任何依赖关系

vector<vector<int>> g(numCourses);

for (auto& p : prerequisites) {

    g[p[1]].push_back(p[0]);

}

步骤 2:DFS 遍历图

接下来,我们使用 DFS 遍历图来检查是否存在环。我们使用一个 colors 数组来标记每个课程的状态:

• colors[i] == 0:课程 i 尚未访问

• colors[i] == 1:课程 i 正在访问中(在当前递归栈中)

• colors[i] == 2:课程 i 已访问完毕

对于每个课程,如果它尚未访问,则启动 DFS:

for (int i = 0; i < numCourses; i++) {

    if (colors[i] == 0 && dfs(i, g, colors)) {

        return false;  // 如果发现环,返回 false

    }

}

步骤 3:DFS 检查环

在 dfs 函数中,我们递归访问课程的前置课程。如果发现正在访问的课程,说明存在环;如果课程已经完全访问过,则跳过。

bool dfs(int x, vector<vector<int>>& g, vector<int>& colors) {

    colors[x] = 1;  // 当前课程 x 正在访问中

    for (int y : g[x]) {  // 遍历课程 x 的所有前置课程 y

        if (colors[y] == 1 || (colors[y] == 0 && dfs(y, g, colors))) {

            return true;  // 如果发现了环:1) y 正在访问中;2) y 尚未访问且递归时发现环

        }

    }

    colors[x] = 2;  // 完全访问完课程 x

    return false;  // 没有发现环

}

代码实现

具体运行步骤

以 numCourses = 4 和 prerequisites = {{1, 0}, {2, 1}, {3, 2}} 为例,具体的运行步骤如下:

1. 构建图

• g[0] = [1]

• g[1] = [2]

• g[2] = [3]

• g[3] = []

2. DFS 遍历图

• 从课程 0 开始,检查它的前置课程,发现课程 1,继续递归。

• 课程 1 的前置课程是课程 2,继续递归。

• 课程 2 的前置课程是课程 3,继续递归。

• 课程 3 没有前置课程,返回并标记为已访问。

• 完成所有课程的遍历,发现没有环。

3. 返回 true:

• 所有课程都没有形成环,因此返回 true,说明可以完成所有课程。

时间复杂度

图构建:时间复杂度为 O(E),其中 E 是 prerequisites 数组中的边数。

DFS 遍历:每个课程和每条依赖边只会被访问一次,因此 DFS 的时间复杂度是 O(V + E),其中 V 是课程数,E 是依赖关系数。

因此,总体时间复杂度是 O(V + E),其中 V 是课程数,E 是依赖关系数。

好的,下面我会为你提供更加详细的运行步骤,并结合一个具体的示例进行演示,帮助你理解如何通过图的 DFS(深度优先搜索)来检测是否能完成所有课程。

题目示例

假设我们有 4 门课程,依赖关系为:

numCourses = 4;

prerequisites = {{1, 0}, {2, 1}, {3, 2}};

这表示:

• 课程 1 依赖于课程 0

• 课程 2 依赖于课程 1

• 课程 3 依赖于课程 2

目标是确定是否能够完成所有课程。如果有环(即课程之间存在循环依赖),则返回 false,否则返回 true。

步骤 1:构建图

首先,我们需要构建图。课程的依赖关系被表示为一个有向图,每个节点代表一门课程,每条边表示一门课程的前置课程。

对于 prerequisites = {{1, 0}, {2, 1}, {3, 2}},图将如下构建:

• 课程 0 -> 课程 1 (课程 1 依赖课程 0)

• 课程 1 -> 课程 2 (课程 2 依赖课程 1)

• 课程 2 -> 课程 3 (课程 3 依赖课程 2)

最终图的结构是:

g[0] = [1]   // 课程 0 -> 课程 1

g[1] = [2]   // 课程 1 -> 课程 2

g[2] = [3]   // 课程 2 -> 课程 3

g[3] = []    // 课程 3 没有依赖

步骤 2:DFS 遍历图

接下来,我们将使用 深度优先搜索(DFS) 来遍历图,并检测是否存在环。我们需要使用一个 colors 数组来标记课程的访问状态:

• 0 表示该课程尚未访问。

• 1 表示该课程正在访问中(即当前递归栈中的课程)。

• 2 表示该课程已完全访问过。

步骤 3:进行 DFS 遍历

初始化

1. 初始化 colors 数组:

vector<int> colors(numCourses, 0);  // 初始值全为 0,表示所有课程都未访问

2. 调用 dfs(i) 来访问每个课程。如果在 DFS 中发现环,则返回 false;否则,返回 true。

具体的 DFS 过程

1. 从课程 0 开始进行 DFS:

• colors[0] 设置为 1,表示课程 0 正在访问中。

• 课程 0 依赖于课程 1,递归调用 dfs(1)。

2. 在 dfs(1) 中:

• colors[1] 设置为 1,表示课程 1 正在访问中。

• 课程 1 依赖于课程 2,递归调用 dfs(2)。

3. 在 dfs(2) 中:

• colors[2] 设置为 1,表示课程 2 正在访问中。

• 课程 2 依赖于课程 3,递归调用 dfs(3)。

4. 在 dfs(3) 中:

• colors[3] 设置为 1,表示课程 3 正在访问中。

• 课程 3 没有依赖课程,所以直接将 colors[3] 设置为 2,表示课程 3 完成访问。

5. 返回到 dfs(2):

• 课程 2 完成访问,colors[2] 设置为 2。

• 返回到 dfs(1)。

6. 返回到 dfs(0):

• 课程 0 完成访问,colors[0] 设置为 2。

• 所有课程都已完成访问。

步骤 4:结果判断

在整个 DFS 遍历过程中,如果没有发现环(即没有遇到 colors[x] == 1 的情况),则说明所有课程都可以完成。

最终,colors 数组的状态为:

colors = {2, 2, 2, 2}

所有课程的状态都为 2,表示它们都已完成访问,没有发现环,因此可以完成所有课程,返回 true。

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

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

相关文章

【HarmonyOS Next】拒绝权限二次申请授权处理

【HarmonyOS Next】拒绝权限二次申请授权处理 一、问题背景&#xff1a; 在鸿蒙系统中&#xff0c;对于用户权限的申请&#xff0c;会有三种用户选择方式&#xff1a; 1.单次使用允许 2.使用应用期间&#xff08;长时&#xff09;允许 3.不允许 当用户选择不允许后&#xff0…

跟着李沐老师学习深度学习(十四)

注意力机制&#xff08;Attention&#xff09; 引入 心理学角度 动物需要在复杂环境下有效关注值得注意的点心理学框架&#xff1a;人类根据随意线索和不随意线索选择注意力 注意力机制 之前所涉及到的卷积、全连接、池化层都只考虑不随意线索而注意力机制则显示的考虑随意…

基于YOLO11深度学习的半导体芯片缺陷检测系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

Spring Boot3.x集成Flowable7.x(一)Spring Boot集成与设计、部署、发起、完成简单流程

一、Flowable简介 Flowable 是一个轻量级、开源的业务流程管理&#xff08;BPM&#xff09;和工作流引擎&#xff0c;旨在帮助开发者和企业实现业务流程的自动化。它支持 BPMN 2.0 标准&#xff0c;适用于各种规模的企业和项目。Flowable 的核心功能包括流程定义、流程执行、任…

网络安全-openssl工具

OpenSSl是一个开源项目&#xff0c;包括密码库和SSL/TLS工具集。它已是在安全领域的事实标准&#xff0c;并且拥有比较长的历史&#xff0c;现在几乎所有的服务器软件和很多客户端都在使用openssl&#xff0c;其中基于命令行的工具是进行加密、证书管理以及测试最常用到的软件。…

【Web开发】PythonAnyWhere免费部署Django项目

PythonAnyWhere免费部署Django项目 文章目录 PythonAnyWhere免费部署Django项目将项目上传到GitHub从GitHub下载Django项目创建Web应用配置静态文件将项目上传到GitHub 打开项目,输入以下命令,生成Django项目依赖包。pip list --format=freeze > requirements.txt打开Git …

视频的分片上传

分片上传需求分析&#xff1a; 项目中很多地方需要上传视频&#xff0c;如果视频很大&#xff0c;上传到服务器需要很多时间 &#xff0c;这个时候体验就会很差。所以需要前端实现分片上传的功能。 要实现分片上传&#xff0c;需要对视频进行分割&#xff0c;分割成不同的大小…

Moonshot AI 新突破:MoBA 为大语言模型长文本处理提效论文速读

前言 在自然语言处理领域&#xff0c;随着大语言模型&#xff08;LLMs&#xff09;不断拓展其阅读、理解和生成文本的能力&#xff0c;如何高效处理长文本成为一项关键挑战。近日&#xff0c;Moonshot AI Research 联合清华大学、浙江大学的研究人员提出了一种创新方法 —— 混…

Deepseek首页实现 HTML

人工智能与未来&#xff1a;机遇与挑战 引言 在过去的几十年里&#xff0c;人工智能&#xff08;AI&#xff09;技术取得了突飞猛进的发展。从语音助手到自动驾驶汽车&#xff0c;AI 正在深刻地改变我们的生活方式、工作方式以及社会结构。然而&#xff0c;随着 AI 技术的普及…

VS2022配置FFMPEG库基础教程

1 简介 1.1 起源与发展历程 FFmpeg诞生于2000年&#xff0c;由法国工程师Fabrice Bellard主导开发&#xff0c;其名称源自"Fast Forward MPEG"&#xff0c;初期定位为多媒体编解码工具。2004年后由Michael Niedermayer接任维护&#xff0c;逐步发展成为包含音视频采…

kafka基本知识

什么是 Kafka&#xff1f; Apache Kafka 是一个开源的分布式流处理平台&#xff0c;最初由 LinkedIn 开发&#xff0c;后来成为 Apache 软件基金会的一部分。Kafka 主要用于构建实时数据管道和流处理应用程序。它能够高效地处理大量的数据流&#xff0c;广泛应用于日志收集、数…

类型系统下的语言分类与类型系统基础

类型系统是一种根据计算值的种类对程序语法进行分类的方式&#xff0c;目的是自动检查是否有可能导致错误的行为。 —Benjamin.C.Pierce&#xff0c;《类型与编程语言》&#xff08;2002&#xff09; 每当谈到编程语言时&#xff0c;人们常常会提到“静态类型”和“动态类型”。…

有没有使用wxpython开发的类似于visio或drawio的开源项目(AI生成)

有没有使用wxpython开发的类似于visio或drawio的开源项目 是的&#xff0c;有一些使用wxPython开发的类似于Microsoft Visio或draw.io&#xff08;现为diagrams.net&#xff09;的开源项目。wxPython 是一个跨平台的GUI工具包&#xff0c;它允许Python开发者创建桌面应用程序&…

【MySQL 一 数据库基础】深入解析 MySQL 的索引(3)

索引 索引操作 自动创建 当我们为一张表加主键约束(Primary key)&#xff0c;外键约束(Foreign Key)&#xff0c;唯一约束(Unique)时&#xff0c;MySQL会为对应的的列自动创建一个索引&#xff1b;如果表不指定任何约束时&#xff0c;MySQL会自动为每一列生成一个索引并用ROW_I…

【C++】优先级队列宝藏岛

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…

List 接口中的 sort 和 forEach 方法

List 接口中的 sort 和 forEach 方法是 Java 8 引入的两个非常实用的函数&#xff0c;分别用于 排序 和 遍历 列表中的元素。以下是它们的详细介绍和用法&#xff1a; sort 函数 功能 对列表中的元素进行排序。 默认使用自然顺序&#xff08;如数字从小到大&#xff0c;字符…

MusicGPT的本地化部署与远程调用:让你的Windows电脑成为AI音乐工作站

文章目录 前言1. 本地部署2. 使用方法介绍3. 内网穿透工具下载安装4. 配置公网地址5. 配置固定公网地址 前言 在如今快节奏的生活里&#xff0c;音乐不仅能够抚慰我们的心灵&#xff0c;还能激发无限创意。想象一下&#xff0c;在忙碌的工作间隙或闲暇时光中&#xff0c;只需输…

Unity通过Vosk实现离线语音识别方法

标注&#xff1a;deepseek直接生成&#xff0c;待验证 在Unity中实现离线语音识别可以通过集成第三方语音识别库来实现。以下是一个使用 Unity 和 Vosk&#xff08;一个开源的离线语音识别库&#xff09;的简单示例。 准备工作 Vosk&#xff1a;一个开源的离线语音识别库&am…

智能优化算法:莲花算法(Lotus flower algorithm,LFA)介绍,提供MATLAB代码

一、 莲花算法 1.1 算法原理 莲花算法&#xff08;Lotus flower algorithm&#xff0c;LFA&#xff09;是一种受自然启发的优化算法&#xff0c;其灵感来源于莲花的自清洁特性和授粉过程。莲花的自清洁特性&#xff0c;即所谓的“莲花效应”&#xff0c;是由其叶片表面的微纳…

企业数据集成:实现高效调拨出库自动化

调拨出库对接调出单-v&#xff1a;旺店通企业奇门数据集成到用友BIP 在企业信息化管理中&#xff0c;数据的高效流转和准确对接是实现业务流程自动化的关键。本文将分享一个实际案例&#xff0c;展示如何通过轻易云数据集成平台&#xff0c;将旺店通企业奇门的数据无缝集成到用…