LeetCode 2050. Parallel Courses III【记忆化搜索,动态规划,拓扑排序】困难

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你一个整数 n ,表示有 n 节课,课程编号从 1n 。同时给你一个二维整数数组 relations ,其中 relations[j] = [prevCoursej, nextCoursej] ,表示课程 prevCoursej 必须在课程 nextCoursej 之前 完成(先修课的关系)。同时给你一个下标从 0 开始的整数数组 time ,其中 time[i] 表示完成第 (i+1) 门课程需要花费的 月份 数。

请你根据以下规则算出完成所有课程所需要的 最少 月份数:

  • 如果一门课的所有先修课都已经完成,你可以在 任意 时间开始这门课程。
  • 你可以 同时任意门课程

请你返回完成所有课程所需要的 最少 月份数。

注意: 测试数据保证一定可以完成所有课程(也就是先修课的关系构成一个有向无环图)。

示例 1:

输入:n = 3, relations = [[1,3],[2,3]], time = [3,2,5]
输出:8
解释:上图展示了输入数据所表示的先修关系图,以及完成每门课程需要花费的时间。
你可以在月份 0 同时开始课程 12 。
课程 1 花费 3 个月,课程 2 花费 2 个月。
所以,最早开始课程 3 的时间是月份 3 ,完成所有课程所需时间为 3 + 5 = 8 个月。

示例 2:

输入:n = 5, relations = [[1,5],[2,5],[3,5],[3,4],[4,5]], time = [1,2,3,4,5]
输出:12
解释:上图展示了输入数据所表示的先修关系图,以及完成每门课程需要花费的时间。
你可以在月份 0 同时开始课程 123 。
在月份 123 分别完成这三门课程。
课程 4 需在课程 3 之后开始,也就是 3 个月后。课程 43 + 4 = 7 月完成。
课程 5 需在课程 1234 之后开始,也就是在 max(1,2,3,7) = 7 月开始。
所以完成所有课程所需的最少时间为 7 + 5 = 12 个月。

提示:

  • 1 <= n <= 5 * 10^4
  • 0 <= relations.length <= min(n * (n - 1) / 2, 5 * 10^4)
  • relations[j].length == 2
  • 1 <= prevCoursej, nextCoursej <= n
  • prevCoursej != nextCoursej
  • 所有的先修课程对 [prevCoursej, nextCoursej] 都是 互不相同 的。
  • time.length == n
  • 1 <= time[i] <= 10^4
  • 先修课程图是一个有向无环图。

本题的实质是求 AOE 图上的最长路径。相似题目:

  • 1857. 有向图中最大颜色值

解法1 记忆化搜索

要求出完成所有课程的最少月份数,可以求出每门课程的最少月份数,然后求出最大值。首先根据 r e l a t i o n s relations relations,构建先修课邻接表表 p r e v prev prev p r e v [ i ] prev[i] prev[i] 就表示课程 i i i 的所有的先修课。定义函数 d p dp dp ,输入参数为 i i i ,返回完成课程 i i i 所需的最少月份数。

  • 如果一门课程 i i i 没有先修课要求,那么完成它的最少月份数就是 t i m e [ i − 1 ] time[i - 1] time[i1]
  • 如果一门课有先修课时,完成它的最少月份数就是在它的所有先修课的最少完成月份的最大值的基础上,再加上 t i m e [ i − 1 ] time[i - 1] time[i1],即 dp [ i ] = max ( d p [ j ] ) + time [ i − 1 ] , j ∈ prev [ i ] \textit{dp}[i] = \textit{max}(dp[j])+\textit{time}[i-1], j\in \textit{prev}[i] dp[i]=max(dp[j])+time[i1],jprev[i]

可以运用记忆化搜索的技巧,求出每门课的最少完成月份数。因为运用了记忆化搜索,每门课的最少完成月份数最多只会被计算一次

class Solution {
public:int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) {int mx = 0;vector<vector<int>> prev(n + 1);for (auto &r : relations) {int x = r[0], y = r[1];prev[y].emplace_back(x);}unordered_map<int, int> rec;function<int(int)> dp = [&](int i) -> int {if (!rec.count(i)) {int cur = 0;for (int p : prev[i]) cur = max(cur, dp(p));cur += time[i - 1];rec[i] = cur;}return rec[i];};for (int i = 1; i <= n; ++i) mx = max(mx, dp(i));return mx;}
};

复杂度分析:

  • 时间复杂度: O ( m + n ) O(m +n) O(m+n),其中 O ( m ) O(m) O(m) 是数组 r e l a t i o n s relations relations 长度。需要构建先修课邻接表表,并且计算每个课程的最少月份数。因为每个课程只会被计算一次,因此相当于是每个 r e l a t i o n relation relation 会被遍历一次。
  • 空间复杂度: O ( m + n ) O(m +n) O(m+n),先修课邻接表表的空间复杂度是 O ( m + n ) O(m +n) O(m+n),记忆化搜索的空间复杂度是 O ( n ) O(n) O(n)

解法2 动态规划

定义 d p [ i ] dp[i] dp[i] 表示完成第 i i i 门课程需要花费的最少月份数。根据题意,只有当 i i i 的所有先修课程都完成时,才可以开始学习第 i i i 门课程,并且可以立即开始。

因此,其中 j j j i i i 的先修课程 f [ i ] = time [ i ] + max ⁡ j f [ j ] f[i]=\textit{time}[i] + \max_{j} f[j] f[i]=time[i]+jmaxf[j]
由于题目保证图是一个有向无环图,所以一定存在拓扑序我们可以在计算拓扑序的同时,计算状态转移

具体来说,设当前节点为 u u u ,我们可以在计算出 d p [ u ] dp[u] dp[u] 后,更新 v v v 的所有先修课程耗时的最大值,这里 u u u v v v 的先修课程。答案就是所有 d p [ i ] dp[i] dp[i] 的最大值。

class Solution {
private:vector<vector<int>> g;
public:int minimumTime(int n, vector<vector<int>>& relations, vector<int>& time) {g.resize(n);vector<int> ind(n);for (vector<int>& r : relations) {int x = r[0] - 1, y = r[1] - 1;g[x].push_back(y); // 建图++ind[y];}// 拓扑排序 queue<int> q;for (int i = 0; i < n; ++i)if (ind[i] == 0) // 没有先修课q.push(i); vector<int> dp(n);int ans = 0;while (!q.empty()) {int u = q.front(); q.pop(); // u出队意味着u的所有先修课都上完了// 出队的顺序就是拓扑序dp[u] += time[u]; // 加上当前课程的时间就得到了最终的dp[u]ans = max(ans, dp[u]);for (int v : g[u]) {dp[v] = max(dp[u], dp[v]); // 更新dp[v]的所有先修课程耗时的最大值if (--ind[v] == 0) { // v的先修课已上完q.push(v); }}}return ans;}  
};

复杂度分析:

  • 时间复杂度: O ( m + n ) O(m+n) O(m+n) ,其中 O ( m ) O(m) O(m) r e l a t i o n s relations relations 的长度。
  • 空间复杂度: O ( m + m ) O(m+m) O(m+m)

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

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

相关文章

多线程之GCD应用

一些套话 GCD全称是Grand Central Dispatch&#xff0c;它是纯 C 语言&#xff0c;并且提供了非常多强大的函数 GCD的优势&#xff1a; GCD 是苹果公司为多核的并行运算提出的解决方案GCD 会自动利用更多的CPU内核&#xff08;比如双核、四核&#xff09;GCD 会自动管理线程的…

SpringBoot+Prometheus+Grafana实现系统可视化监控

场景 SpringBoot中集成Actuator实现监控系统运行状态&#xff1a; SpringBoot中集成Actuator实现监控系统运行状态_springboot actuator 获取系统运行时长_霸道流氓气质的博客-CSDN博客 基于以上Actuator实现系统监控&#xff0c;还可采用如下方案。 Prometheus Prometheu…

Selenium基础篇之屏幕截图方法

文章目录 前言一、用途1.捕获页面错误2.调试测试用例3.展示测试结果4.记录页面状态 二、方法1. save_screenshot2. get_screenshot_as_file3. get_screenshot_as_png4. get_screenshot_as_base64 总结 前言 大家好&#xff0c;我是空空star&#xff0c;本篇给大家分享一下Selen…

CMU 15-445 -- Logging Schemes - 17

CMU 15-445 -- Logging Schemes - 17 引言IndexFailure ClassificationTransaction FailuresSystem FailuresStorage Media Failures Buffer Pool PoliciesShadow Paging: No-Steal ForceWrite-Ahead Log (WAL): Steal No-ForceLogging SchemesCheckpoints小结 引言 本系列为…

IDEA配置远程docker解释器及无编码提示/关联不到python依赖问题

文章目录 1. 修改docker默认配置以支持远程连接2. 配置docker远程解释器3 .IDE配置project SDK4. 本地代码与Linux目录映射5.运行配置 1. 修改docker默认配置以支持远程连接 vim /lib/systemd/system/docker.service,修改docker启动参数 #ExecStart/usr/bin/dockerd -H fd://…

c++学习(c++11)[24]

c11 列表初始化 #include"iostream" using namepace std;int main() {int x1 1;int x2 { 2 };int x3 { 2 };vector<int> v1 {1,2,3,4,5,6};vector<int> v1 {1,2,3,4,5,6};list<int> lt1 {1,2,3,4,5,6};list<int> lt1 {1,2,3,4,5,6};au…

Python(四十九)获取列表指定元素的索引

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

汇编调用C语言定义的全局变量

在threadx移植中&#xff0c;系统的systick通过了宏定义的方式定义&#xff0c;很难对接库函数的时钟频率&#xff0c;不太利于进行维护 所以在C文件中自己定义了一个systick_Div的变量&#xff0c;通过宏定义方式设定systick的时钟频率 在汇编下要加载这个systick分频系数 …

UDS诊断协议

UDS本质上是一系列服务的集合&#xff0c;包含6大类&#xff0c;共26种。每种服务都有独立的ID&#xff0c;即SID。 请求 SID(1Byte) 参数 SID(1Byte) Sub-function(1Byte) 参数 SID DID(2Bytes) 响应 肯定响应 SID0x40(1Byte) Sub-function(根据请求是否存在) 参数…

Windows数据类型LPSTR学习

Windows在C语言的基础之上又定义了一些Windows下的数据类型&#xff1b;下面学习一下LPSTR&#xff1b; LPSTR和LPWSTR是Win32和VC所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的32位ANSI字符数组指针&#xff0c;而LPWSTR是一个指向以NULL结尾的64…

2023年基准Kubernetes报告:6个K8s可靠性失误

云计算日益成为组织构建应用程序和服务的首选目的地。尽管一年来经济不确定性的头条新闻主要集中在通货膨胀增长和银行动荡方面&#xff0c;但大多数组织预计今年的云使用和支出将与计划的相同&#xff08;45%&#xff09;&#xff0c;或高于计划的&#xff08;45%&#xff09;…

大数据Flink(五十三):Flink流处理特性、发展历史以及Flink的优势

文章目录 Flink流处理特性、发展历史以及Flink的优势 一、Flink流处理特性 二、发展历史

opencv-28 自适应阈值处理-cv2.adaptiveThreshold()

什么是自适应阈值处理? 对于色彩均衡的图像&#xff0c;直接使用一个阈值就能完成对图像的阈值化处理。但是&#xff0c;有时图像的色彩是不均衡的&#xff0c;此时如果只使用一个阈值&#xff0c;就无法得到清晰有效的阈值分割结果图像。 有一种改进的阈值处理技术&#xff…

五、控制流(2)

本章概要 returnbreak 和 continue臭名昭著的 gotoswitchswitch 字符串 return 在 Java 中有几个关键字代表无条件分支&#xff0c;这意味无需任何测试即可发生。这些关键字包括 return&#xff0c;break&#xff0c;continue 和跳转到带标签语句的方法&#xff0c;类似于其…

不管如何吐槽,购买iPhone的用户依然义无反顾,苹果继续增长

市调机构IDC公布的二季度数据显示&#xff0c;苹果成为前五名之中除华为之外第二家取得增长的手机品牌&#xff0c;而其他国产手机品牌的出货量都在下滑&#xff0c;显示出国内的消费者仍然在热烈追捧iPhone。 二季度苹果在国内市场的手机出货量同比增长6%&#xff0c;虽然增速…

Android Studio下载及安装和Gradle的配置

文章目录 下载安装修改Sdk的位置创建项目修改Gradle的位置查看AS版本工具栏--View项工具栏--Build下的功能说明Build Variants视图说明下载模拟器&#xff08;avd&#xff09;/安卓虚拟设备屏幕熄灭功能关闭虚拟设备功能删除自己开发的应用软件将开发的应用运行到虚拟设备上。 …

从分片传输到并行传输之大文件传输加速技术

随着大文件的传输需求越来越多&#xff0c;传输过程中也会遇到很多困难&#xff0c;比如传输速度慢、文件安全性低等。为了克服这些困难&#xff0c;探讨各种大文件传输加速技术。其中&#xff0c;分片传输和并行传输是两种比较常见的技术&#xff0c;下面将对它们进行详细说明…

Java版知识付费源码 Spring Cloud+Spring Boot+Mybatis+uniapp+前后端分离实现知识付费平台

提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含&#xff1a;录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署&#xff0c;免费售后&#xff0c;专业技术指导&#xff0c;支持PC、APP、H5、小程序多终端同步&#xff0c;支持二次开发…

【Java】Java多线程编程基础

文章目录 1. 进程与线程1.1 进程与线程的基本认识1.1.1 进程&#xff08;Process&#xff09;1.1.2 线程&#xff08;Thread&#xff09; 1.2 为什么会有线程1.2.1 以看视频为例 2. 多线程实现2.1 Thread类实现多线程2.2 Runnable接口实现多线程2.3 Callable接口实现多线程2.3 …

CTF线下赛AWD知识点【持续完善ing】

文章目录 CTF线下赛AWD知识点AWD规则前期准备SSH登录口令登录密钥登录 改密码SSH密码修改mysql密码修改 备份数据备份目录备份数据库 查找后门 自动提交flag防御思路基础查杀寻找最近20分钟修改过的文件寻找行数最短的文件关键字查杀查找命令执行函数 文件监控杀不死马0x01.杀进…