LeetCode 630. Course Schedule III【反悔贪心,堆,排序】中等

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

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

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

这里有 n 门不同的在线课程,按从 1 到 n 编号。给你一个数组 courses ,其中 courses[i] = [durationi, lastDayi] 表示第 i 门课将会 持续 上 durationi 天课,并且必须在不晚于 lastDayi 的时候完成。

你的学期从第 1 天开始。且不能同时修读两门及两门以上的课程。

返回你最多可以修读的课程数目。

示例 1:

输入:courses = [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]
输出:3
解释:
这里一共有 4 门课程,但是你最多可以修 3 门:
首先,修第 1 门课,耗费 100 天,在第 100 天完成,在第 101 天开始下门课。
第二,修第 3 门课,耗费 1000 天,在第 1100 天完成,在第 1101 天开始下门课程。
第三,修第 2 门课,耗时 200 天,在第 1300 天完成。
第 4 门课现在不能修,因为将会在第 3300 天完成它,这已经超出了关闭日期。

示例 2:

输入:courses = [[1,2]]
输出:1

示例 3:

输入:courses = [[3,2],[4,3]]
输出:0

提示:

  • 1 <= courses.length <= 10^4
  • 1 <= durationi, lastDayi <= 10^4

这个题和他左右两个邻居来自同一场周赛,而且这道题只是第二题…… 当时美服共有超过2000人参赛,除了前112名,都是一题选手……

解法 反悔贪心+堆

思路

这道题很有意义,是一道经典贪心运用题——题目要求我们构造一种可行的课程排列,排列中每门课程的实际结束时间「不超过最晚截止时间 lastDayi」,求最长可行排列的长度。

对于两门课 ( t 1 , d 1 ) (t_1, d_1) (t1,d1) ( t 2 , d 2 ) (t_2, d_2) (t2,d2) ,如果后者的关闭时间较晚,即 d 1 ≤ d 2 d_1 \leq d_2 d1d2 ,那么我们先学习前者,再学习后者,总是最优的。这是因为:

  • 设开始学习的时间点为 x x x 。如果先学习前者,再学习后者,那么需要满足:
    { x + t 1 ≤ d 1 x + t 1 + t 2 ≤ d 2 \begin{cases} x + t_1 \leq d_1 \\ x + t_1 + t_2 \leq d_2 \end{cases} {x+t1d1x+t1+t2d2
  • 如果先学习后者,再学习前者,那么需要满足:
    { x + t 2 ≤ d 2 x + t 2 + t 1 ≤ d 1 \begin{cases} x + t_2 \leq d_2 \\ x + t_2 + t_1 \leq d_1 \end{cases} {x+t2d2x+t2+t1d1
    如果 x + t 2 + t 1 ≤ d 1 x + t_2 + t_1 \leq d_1 x+t2+t1d1 成立,由于 d 1 ≤ d 2 d_1 \leq d_2 d1d2 ,那么 x + t 1 ≤ d 1 x + t_1 \leq d_1 x+t1d1 x + t 1 + t 2 ≤ d 2 x + t_1 + t_2 \leq d_2 x+t1+t2d2 同时成立。这说明如果能「先学习后者,再学习前者」那么一定能「先学习前者,再学习后者」。反之如果 x + t 1 + t 2 ≤ d 2 x + t_1 + t_2 \leq d_2 x+t1+t2d2 成立,则不能推出 x + t 2 + t 1 ≤ d 1 x + t_2 + t_1 \leq d_1 x+t2+t1d1 成立,例如当 x = 0 x = 0 x=0 ( t 1 , d 1 ) = ( 2 , 3 ) (t_1, d_1) = (2, 3) (t1,d1)=(2,3) ( t 2 , d 2 ) = ( 5 , 100 ) (t_2, d_2) = (5, 100) (t2,d2)=(5,100) 时,虽然能「先学习前者,再学习后者」,但不能「先学习后者,再学习前者」。

因此,我们可以将所有的课程按照关闭时间 d d d 进行升序排序,再依次挑选课程并按照顺序进行学习。

在遍历的过程中,假设我们当前遍历到了第 i i i 门课 ( t i , d i ) (t_i, d_i) (ti,di) ,而在前 i − 1 i-1 i1 门课程中我们选择了 k k k 门课 ( t x 1 , d x 1 ) , ( t x 2 , d x 2 ) , ⋯ , ( t x k , d x k ) (t_{x_1}, d_{x_1}), (t_{x_2}, d_{x_2}), \cdots, (t_{x_k}, d_{x_k}) (tx1,dx1),(tx2,dx2),,(txk,dxk) ,满足 x 1 < x 2 < ⋯ < x k x_1 < x_2 < \cdots < x_k x1<x2<<xk ,那么有:
{ t x 1 ≤ d x 1 t x 1 + t x 2 ≤ d x 2 ⋯ t x 1 + t x 2 + ⋯ + t x k ≤ d x k \begin{cases} t_{x_1} \leq d_{x_1} \\ t_{x_1} + t_{x_2} \leq d_{x_2} \\ \cdots \\ t_{x_1} + t_{x_2} + \cdots + t_{x_k} \leq d_{x_k} \end{cases} tx1dx1tx1+tx2dx2tx1+tx2++txkdxk

如果上述选择方案是前 i − 1 i-1 i1 门课程的「最优方案」:即不存在能选择 k + 1 k+1 k+1 门课程的方法,也不存在能选择 k k k 门课程,并且总时长更短(小于 t x 1 + t x 2 + ⋯ + t x k t_{x_1} + t_{x_2} + \cdots + t_{x_k} tx1+tx2++txk )的方案,那么我们可以基于该方案与第 i i i 门课程 ( t i , d i ) (t_i, d_i) (ti,di) ,构造出前 i i i 门课程的最优方案

  • 如果 t x 1 + t x 2 + ⋯ + t x k + t i ≤ d i t_{x_1} + t_{x_2} + \cdots + t_{x_k} + t_i \leq d_i tx1+tx2++txk+tidi ,那么我们可以将第 i i i 门课程 ( t i , d i ) (t_i, d_i) (ti,di) 直接加入方案,得到选择 k + 1 k+1 k+1 门课程的最优方案
    此处的「最优性」可以使用反证法来证明—— 如果存在更优的方案,那么该方案一定包含 ( t i , d i ) (t_i, d_i) (ti,di) ,如果不包含,那么说明前 i − 1 i-1 i1 门课程就存在更优的方案,这与我们的假设相矛盾。
    当最优方案包含 ( t i , d i ) (t_i, d_i) (ti,di) 时,根据之前的证明,「先学习前者,再学习后者」总是最优的,我们就可以把 ( t i , d i ) (t_i, d_i) (ti,di) 作为该方案的最后一门课程。由于该最优方案优于选择 x 1 , x 2 , ⋯ , x k , i x_1, x_2, \cdots, x_k, i x1,x2,,xk,i 的构造方案,因此同时将最后一门课程 i i i 去除后,该方案仍然优于选择 x 1 , x 2 , ⋯ , x k x_1, x_2, \cdots, x_k x1,x2,,xk 的方案,同样说明前 i − 1 i-1 i1 门课程存在更优的方案,这与我们的假设相矛盾。
  • 如果 t x 1 + t x 2 + ⋯ + t x k + t i > d i t_{x_1} + t_{x_2} + \cdots + t_{x_k} + t_i > d_i tx1+tx2++txk+ti>di ​,那么我们无法将第 i i i 门课程 ( t i , d i ) (t_i, d_i) (ti,di) 直接加入方案。我们可以使用类似的反证法,证明出此时前 i i i 门课程不可能存在选择 k + 1 k+1 k+1 门课程的更优方案,因此我们的目标仍然为选择 k k k 门课程,但最小化它们的总时间,为后续的课程腾出更多的时间
    • 如果 t x 1 , t x 2 , ⋯ , t x k t_{x_1}, t_{x_2}, \cdots, t_{x_k} tx1,tx2,,txk 都小于等于 t i t_i ti ,那么我们显然没有办法通过第 i i i 门课来使得总时间更小。但如果其中时间最长的那门课(记为 t x j t_{x_j} txj 满足 t x j > t i t_{x_j} > t_i txj>ti ,那么我们就可以尝试将第 x j x_j xj 门课程替换成第 i i i 门课程了。这样的替换会使得总时间减少 t x j − t i t_{x_j} - t_i txjti ​,也是我们能做到的减少的上限了
      那么将第 x j x_j xj 门课程替换成第 i i i 门课程后,这些课程是否满足题目的要求呢?我们将这些课程按照 x 1 , x 2 , ⋯ , x j − 1 , x j + 1 , ⋯ , x k , i x_1, x_2, \cdots, x_{j-1}, x_{j+1}, \cdots, x_k, i x1,x2,,xj1,xj+1,,xk,i 的顺序进行学习:
      • 对于 x 1 , x 2 , ⋯ , x j − 1 x_1, x_2, \cdots, x_{j-1} x1,x2,,xj1 ,它们需要满足的不等式与之前是一致的,因此仍然满足要求;
      • 对于 x j + 1 , ⋯ , x k x_{j+1}, \cdots, x_{k} xj+1,,xk ,原先需要满足的不等式的左侧少了 t x j t_{x_j} txj 这一项,由于是左侧 ≤ ≤ 右侧,因此仍然满足要求;
      • 对于 i i i,由于 t x 1 + t x 2 + ⋯ + t x k ≤ d x k t_{x_1} + t_{x_2} + \cdots + t_{x_k} \leq d_{x_k} tx1+tx2++txkdxk 成立,而 t x j > t i t_{x_{j}} > t_i txj>ti ,因此:
        t x 1 + t x 2 + ⋯ + t x j − 1 + t x j + 1 + ⋯ + t x k + t i ≤ d x k t_{x_1} + t_{x_2} + \cdots + t_{x_{j-1}} + t_{x_{j+1}} + \cdots + t_{x_k} + t_i \leq d_{x_k} tx1+tx2++txj1+txj+1++txk+tidxk
        满足要求。

这就说明我们可以将第 x j x_j xj 门课程替换成第 i i i 门课程。这样一来,当我们遍历完所有的 n n n 门课程后,就可以得到最终的答案。

算法

我们需要一个数据结构支持「取出 t t t 值最大的那门课程」,因此我们可以使用优先队列(大根堆)。我们依次遍历每一门课程,当遍历到 ( t i , d i ) (t_i, d_i) (ti,di) 时:

  • 如果当前优先队列中所有课程的总时间与 t i t_i ti 之和小于等于 d i d_i di ,那么我们就把 t i t_i ti 加入优先队列中;
  • 如果当前优先队列中所有课程的总时间与 t i t_i ti​ 之和大于 d i d_i di ,那么我们找到优先队列中的最大元素 t x j t_{x_j} txj 。如果 t x j > t i t_{x_j} > t_i txj>ti ,则将它移出优先队列,并把 t i t_i ti​ 加入优先队列中。

在遍历完成后,优先队列中包含的元素个数即为答案。

class Solution {
public:int scheduleCourse(vector<vector<int>>& courses) {sort(courses.begin(), courses.end(), [](const auto &c0, const auto &c1) {return c0[1] < c1[1];});priority_queue<int> q;// 优先队列中所有课程的总时间int total = 0;for (const auto &course : courses) {int ti = course[0], di = course[1];if (total + ti <= di) {total += ti;q.push(ti);} else if (!q.empty() && q.top() > ti) {total -= q.top() - ti;q.pop();q.push(ti);}}return q.size();}
};

复杂度分析:

  • 时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn) 。排序需要 O ( n log ⁡ n ) O(n\log n) O(nlogn) 的时间,优先队列的单次操作需要 O ( log ⁡ n ) O(\log n) O(logn) 的时间,每个任务会最多被放入和取出优先队列一次,这一部分的时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn) 。因此总时间复杂度也为 O ( n log ⁡ n ) O(n\log n) O(nlogn)
  • 空间复杂度: O ( n ) O(n) O(n) ,即为优先队列需要使用的空间。

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

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

相关文章

Progresql数据库安装--安装

--安装progresql数据库 systemctl disable firewalld systemctl status firewalld systemctl stop firewalld --准备工作 yum install epel-release.noarch -y yum install libzstd.x86_64 -y # Install the repository RPM: s sudo yum install -y https://download.postgresq…

SpringMVC的简介及工作流程

一.简介 Spring MVC是一个基于Java的开发框架&#xff0c;用于构建灵活且功能强大的Web应用程序。它是Spring Framework的一部分&#xff0c;提供了一种模型-视图-控制器&#xff08;Model-View-Controller&#xff0c;MVC&#xff09;的设计模式&#xff0c;用于组织和管理Web…

MATLAB中isoutlier函数用法

目录 语法 说明 示例 检测向量中的离群值 使用均值检测方法 使用移窗检测法 检测矩阵中的离群值 可视化离群值阈值 isoutlier函数的功能是查找数据中的离群值 语法 TF isoutlier(A) TF isoutlier(A,method) TF isoutlier(A,"percentiles",threshold) TF…

你们分库分表使用什么中间件,有什么优点和缺点?

分析&回答 根据自己的实际使用来说&#xff1a; cobar 阿里 b2b 团队开发和开源的&#xff0c;属于 proxy 层方案。早些年还可以用&#xff0c;但是最近几年都没更新了&#xff0c;基本没啥人用&#xff0c;差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨…

【React】React学习:从初级到高级(四)

React学习[四] 4 应急方案4.1 使用ref引用值4.1.1 给组件添加ref4.1.2 ref和state的不同之处4.1.3 何时使用ref 4.2 使用ref操作DOM4.2.1 获取指向节点的ref4.2.3 使用 ref 回调管理 ref 列表4.2.4 访问另一个组件的DOM节点4.2.5 用 flushSync 同步更新 state 4.3 使用Effect同…

controller接口上带@PreAuthorize的注解如何访问 (postman请求示例)

1. 访问接口 /*** 查询时段列表*/RateLimiter(time 10,count 10)ApiOperation("查询时段列表")PreAuthorize("ss.hasPermi(ls/sy:time:list)")GetMapping("/list")public TableDataInfo list(LsTime lsTime){startPage();List<LsTime> l…

01 PHP基础知识讲解

一 php基础知识 PHP文件的默认拓展名是“php”。 PHP文件中包含HTML标记、PHP标记、PHP代码以及空格和注释。 PHP标记&#xff1a;开始标记<?php 结束标记 ?> 中间内容是PHP代码。 PHP代码&#xff1a;学习第一个指令 echo 功能是用于输出字符串 。 语句结束符&a…

Kotlin+MVVM 构建todo App 应用

作者&#xff1a;易科 项目介绍 使用KotlinMVVM实现的todo app&#xff0c;功能界面参考微软的Todo软件&#xff08;只实现了核心功能&#xff0c;部分功能未实现&#xff09;。 功能模块介绍 项目模块&#xff1a;添加/删除项目&#xff0c;项目负责管理todo任务任务模块&a…

信息化发展29

虚拟现实概述 建立一个能包容图像、声音、化学气味等多种信息源的信息空间&#xff0c; 将其与视觉、听觉、嗅觉、口令、手势等人类的生活空间交叉融&#xff0c; 虚拟现实的技术应运而生。 1 、虚拟现实技术的主要特征包括沉浸性、交互性、多感知性、构想性&#xff08;也称想…

时序分解 | MATLAB实现MVMD多元变分模态分解信号分量可视化

时序分解 | MATLAB实现MVMD多元变分模态分解信号分量可视化 目录 时序分解 | MATLAB实现MVMD多元变分模态分解信号分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 MVMD多元变分模态分解 可直接替换Excel运行包含频谱相关系数图 Matlab语言 1.算法新颖小众&…

Matlab之数组字符串函数汇总

一、前言 在MATLAB中&#xff0c;数组字符串是指由字符组成的一维数组。字符串可以包含字母、数字、标点符号和空格等字符。MATLAB提供了一些函数和操作符来创建、访问和操作字符串数组。 二、字符串数组具体怎么使用&#xff1f; 1、使用单引号或双引号括起来的字符序列 例…

数据结构 - 双向链表

文章目录 目录 文章目录 前言 一、什么是双向链表? 双向链表有什么优势? 二、双向链表的设计和实现 1.设计思想 尾增 : 在链表的末尾添加新的元素 头插 : 在链表头部插入节点 删除 : 根据val的值删除节点 查找 : 根据索引的值查找并返回节点 总结 前言 大家好,今天给…

Linux TCP和UDP协议

目录 TCP协议TCP协议的面向连接1.三次握手2.四次挥手 TCP协议的可靠性1.TCP状态转移——TIME_WAIT 状态TIME_WAIT 状态存在的意义&#xff1a;&#xff08;1&#xff09;可靠的终止TCP连接。&#xff08;2&#xff09;让迟来的TCP报文有足够的时间被识别并被丢弃。 2.应答确认、…

Google Chrome 浏览器以全屏模式打开

目录 前言以全屏模式打开禁止弹出无法更新的提示窗禁止翻译网页Chrome设置禁止翻译网页可能1可能2可能3 网页添加指令禁止Chrome翻译网页 禁用脚本气泡浏览器解决办法html解决办法方法1&#xff1a;鼠标滑过超链接时&#xff0c;使状态栏不出现超链接方法2&#xff1a;方法3&am…

微服务06-Dockerfile自定义镜像+DockerCompose部署多个镜像

常见的镜像在DockerHub能找到&#xff0c;但是我们自己写项目得自己构造镜像 1 镜像结构 作用&#xff1a;提高复用性&#xff0c;当应用需要更新时&#xff0c;不再是整个系统重装进行更新 &#xff0c;而是对需要更新的部分进行更新&#xff0c;其他地方不动——>这就是分…

如何写出一篇爆款产品文案,从目标受众到市场分析!

一篇爆款产品文案意味着什么?意味着更强的种草能力&#xff0c;更高的销售转化和更强的品牌传播力。今天来分享下如何写出一篇爆款产品文案&#xff0c;从目标受众到市场分析&#xff01; 一、产品文案策略 一篇爆款产品文案&#xff0c;并不是一时兴起造就的。在撰写之前&…

【PowerQuery】Excel和PowerBI的PowerQuery 数据刷新

数据的刷新是在进行数据集成和清洗过程中非常重要的条件,试想你做了100多个不同数据来源的数据集成,如果你再添加了100个文件还需要重新再来数据集成和清洗一遍的话,你的工作量其实一点也没有减轻反而更重了,这个事情变得做起来就没有任何意义。而PowerQuery的最大优势就在…

解决报错之org.aspectj.lang不存在

一、IDEA在使用时&#xff0c;可能会遇到maven依赖包明明存在&#xff0c;但是build或者启动时&#xff0c;报找不存在。 解决办法&#xff1a;第一时间检查Setting->Maven-Runner红圈中的√有没有选上。 二、有时候&#xff0c;明明依赖包存在&#xff0c;但是Maven页签中…

录音新手必备,2款音频录制软件推荐!

“有好用的音频录制软件推荐吗&#xff1f;最近需要录制歌曲去参加一个线上的歌手大赛&#xff0c;只需要上传自己录制的音乐就可以了&#xff0c;但是录音软件的质量太差了&#xff0c;就想问问有没有好用的音频录制软件&#xff0c;谢谢。” 随着数字化时代的到来&#xff0…

MATLAB实现函数拟合

目录 一.理论知识 1.拟合与插值的区别 2.几何意义 3.误差分析 二.操作实现 1.数据准备 2.使用cftool——拟合工具箱 三.函数拟合典例 四.代码扩展 一.理论知识 1.拟合与插值的区别 通俗的说&#xff0c;插值的本质是根据现有离散点的信息创建出更多的离散点&#xf…