【反悔贪心】【优先队列】3049. 标记所有下标的最早秒数 II

本文涉及知识点

反悔贪心 堆(优先队列)
二分查找算法合集

LeetCode3049. 标记所有下标的最早秒数 II

给你两个下标从 1 开始的整数数组 nums 和 changeIndices ,数组的长度分别为 n 和 m 。
一开始,nums 中所有下标都是未标记的,你的任务是标记 nums 中 所有 下标。
从第 1 秒到第 m 秒(包括 第 m 秒),对于每一秒 s ,你可以执行以下操作 之一 :
选择范围 [1, n] 中的一个下标 i ,并且将 nums[i] 减少 1 。
将 nums[changeIndices[s]] 设置成任意的 非负 整数。
选择范围 [1, n] 中的一个下标 i , 满足 nums[i] 等于 0, 并 标记 下标 i 。
什么也不做。
请你返回范围 [1, m] 中的一个整数,表示最优操作下,标记 nums 中 所有 下标的 最早秒数 ,如果无法标记所有下标,返回 -1 。

示例 1:
输入:nums = [3,2,3], changeIndices = [1,3,2,2,2,2,3]
输出:6
解释:这个例子中,我们总共有 7 秒。按照以下操作标记所有下标:
第 1 秒:将 nums[changeIndices[1]] 变为 0 。nums 变为 [0,2,3] 。
第 2 秒:将 nums[changeIndices[2]] 变为 0 。nums 变为 [0,2,0] 。
第 3 秒:将 nums[changeIndices[3]] 变为 0 。nums 变为 [0,0,0] 。
第 4 秒:标记下标 1 ,因为 nums[1] 等于 0 。
第 5 秒:标记下标 2 ,因为 nums[2] 等于 0 。
第 6 秒:标记下标 3 ,因为 nums[3] 等于 0 。
现在所有下标已被标记。
最早可以在第 6 秒标记所有下标。
所以答案是 6 。
示例 2:
输入:nums = [0,0,1,2], changeIndices = [1,2,1,2,1,2,1,2]
输出:7
解释:这个例子中,我们总共有 8 秒。按照以下操作标记所有下标:
第 1 秒:标记下标 1 ,因为 nums[1] 等于 0 。
第 2 秒:标记下标 2 ,因为 nums[2] 等于 0 。
第 3 秒:将 nums[4] 减少 1 。nums 变为 [0,0,1,1] 。
第 4 秒:将 nums[4] 减少 1 。nums 变为 [0,0,1,0] 。
第 5 秒:将 nums[3] 减少 1 。nums 变为 [0,0,0,0] 。
第 6 秒:标记下标 3 ,因为 nums[3] 等于 0 。
第 7 秒:标记下标 4 ,因为 nums[4] 等于 0 。
现在所有下标已被标记。
最早可以在第 7 秒标记所有下标。
所以答案是 7 。
示例 3:
输入:nums = [1,2,3], changeIndices = [1,2,3]
输出:-1
解释:这个例子中,无法标记所有下标,因为我们没有足够的秒数。
所以答案是 -1 。

提示:
1 <= n == nums.length <= 5000
0 <= nums[i] <= 109
1 <= m == changeIndices.length <= 5000
1 <= changeIndices[i] <= n

反悔贪心

changeIndices[i]都减一,下标转为从0开始。
本题 ⟺ \iff 有n门课,自学需要nums[i]天;第i天有changeIndices[i]的网课,无论此课程难易,一天都可以学会。无论是自学还是上课,学习后都需要一天考试。
性质一:一门课,要么自学,要么上课,不会两者皆有。
性质二:上课必须在指定的那几天,所以可能导致有些天无事课干。比如:{2,0} {1,1,1,0},如果课程0 上网课,则需要5天。前3天有两天无事可做。自学随时可以进行,所以不会导致无事可干。
性质三:一门课第t1天和t2天有课,t1 < t2,t1学习不劣于t2学习。
性质四: mid1<mid2,如果mid1天能完成 学习,则mid2天一定能完成学习。我寻找第一个能完成学习的mid,即确定mid能学习后,还要在(left,mid]继续找。故用左开右闭空间的二分查找。

mid天能否完成学习

从后到前枚举第i天,符合以下两个条件,则试图学习:
一,当天的课程,自学超过1天。
二,第i天之前没有当天的课。
第i天及之后,最多可以学习canStudy = (mid-i)/2 门课程。
{ 学习当前课程 已学课程 < c a n S t u d y 贪心 试图替换已学课程 o t h e r 返回 \begin{cases} 学习当前课程 && 已学课程 < canStudy && 贪心 \\ 试图替换已学课程 && other && 返回 \\ \end{cases} {学习当前课程试图替换已学课程已学课程<canStudyother贪心返回
试图替换:如果已学课程自学用时小于当前课程的自学用时,则替换。
性质五:如果t1 < t2,t1学习,t2不学习引起的“无事可做”天数 <= t2学习,t1不学习 引起的“无事可做”天数。如果t1 自学的课程用时更多,则替换后的用时减少或不变。
下面来证明这样做是最优解:
一,如果nums[i] >=2 ,上课没有引起考试超过mid天,则上课一定优于自学。
二,某门课没有上课,说明它被淘汰了。

代码

核心代码

namespace NBinarySearch
{template<class INDEX_TYPE, class _Pr>INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr){while (rightInclue - left > 1){const auto mid = left + (rightInclue - left) / 2;if (pr(mid)){rightInclue = mid;}else{left = mid;}}return rightInclue;}template<class INDEX_TYPE, class _Pr>INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr){while (right - leftInclude > 1){const auto mid = leftInclude + (right - leftInclude) / 2;if (pr(mid)){leftInclude = mid;}else{right = mid;}}return leftInclude;}
}class Solution {
public:int earliestSecondToMarkIndices(vector<int>& nums, vector<int>& changeIndices) {vector<bool> vCanQuick(nums.size());for (auto& n : changeIndices){n--;if(vCanQuick[n]){n = -1;}else{vCanQuick[n] = true;}}auto Can = [&](int mid){std::priority_queue<int, vector<int>, std::greater<>> minHeap;for (int i = mid - 1; i >= 0; i--){const int iStudy = changeIndices[i];if ((-1 == iStudy) || (nums[iStudy] < 2)){continue;}if ((mid - i) / 2 > minHeap.size()){minHeap.emplace(nums[iStudy]);}else if (minHeap.size() && (minHeap.top() < nums[iStudy])){minHeap.pop();minHeap.emplace(nums[iStudy]);}}long long llNeed = std::accumulate(nums.begin(), nums.end(), 0LL) + nums.size();//自学考试总用时const int iRemain = mid - minHeap.size();//可以用于考试、自学的时间while (minHeap.size()) {llNeed -= minHeap.top();minHeap.pop();}return iRemain >= llNeed;};int iRet =  NBinarySearch::FindFrist(-1, (int)changeIndices.size(), Can);return Can(iRet) ? iRet : -1;}
};

测试用例

template<class T, class T2>
void Assert(const T& t1, const T2& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{vector<int> nums, changeIndices;{Solution sln;nums = { 0,2,0,1 }, changeIndices = { 2,3,2,3,4,4,1,3 };auto res = sln.earliestSecondToMarkIndices(nums, changeIndices);Assert(6, res);}{Solution sln;nums = { 3, 2, 3 }, changeIndices = { 1, 3, 2, 2, 2, 2, 3 };auto res = sln.earliestSecondToMarkIndices(nums, changeIndices);Assert(6, res);}{Solution sln;nums = { 0,0,1,2 }, changeIndices = { 1,2,1,2,1,2,1,2 };auto res = sln.earliestSecondToMarkIndices(nums, changeIndices);Assert(7, res);}{Solution sln;nums = { 1,2,3 }, changeIndices = { 1,2,3 };auto res = sln.earliestSecondToMarkIndices(nums, changeIndices);Assert(-1, res);}	
}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

抽象类 与 接口 的区别

前言 这个知识点我之前就已经学过&#xff0c;但是我学的半桶水&#xff0c;就是只理解了比较表面的意思。我第一次面试的时候&#xff0c;面试官刚好就问了我这个问题&#xff0c;我一紧张&#xff0c;回答的磕磕绊绊的&#xff0c;很是尴尬。之后我就反思&#xff0c;发现其…

WordPress外贸建站Astra免费版教程指南(2024)

在WordPress的外贸建站主题中&#xff0c;有许多备受欢迎的主题&#xff0c;如Avada、Astra、Hello、Kadence等最佳WordPress外贸主题&#xff0c;它们都能满足建站需求并在市场上广受认可。然而&#xff0c;今天我要介绍的是一个不断颠覆建站人员思维的黑马——Astra主题。 原…

注册接口和前置SQL及数据生成及封装

注册接口 演示注册接口的三步操作&#xff1a;【注册流程逻辑】 第一步&#xff1a;发送注册短信验证码接口请求 请求方法&#xff1a; put 请求地址&#xff1a;http://shop.lemonban.com:8107/user/sendRegisterSms 请求参数&#xff1a;{“mobile”:“13422337766”} 请求头…

[实时流基础 flink] 窗口

在批处理统计中&#xff0c;我们可以等待一批数据都到齐后&#xff0c;统一处理。但是在实时处理统计中&#xff0c;我们是来一条就得处理一条&#xff0c;那么我们怎么统计最近一段时间内的数据呢&#xff1f;引入“窗口”。 文章目录 6.1 窗口的概念6.2 窗口的分类**1&#x…

C语言第三十八弹---编译和链接

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 编译和链接 1、翻译环境和运行环境 2、翻译环境 2.1、预处理&#xff08;预编译&#xff09; 2.2、编译 2.2.1、词法分析 2.2.2、语法分析 2.2.3、语义分…

rs485自动收发电路

R/RO&#xff1a;receive/receive out&#xff0c;接收&#xff0c;连接单片机的 rx D/DI&#xff1a;drive/drive in&#xff0c;驱动&#xff0c;连接单片机的 tx 自动控制电路的目的就是在 tx 空闲&#xff08;空闲为高并&#xff09;时拉低 RE 和 DE&#xff0c;工作&…

open Gauss 数据库-04 openGauss数据库日志管理指导手册

发文章是为了证明自己真的掌握了一个知识&#xff0c;同时给他人带来帮助&#xff0c;如有问题&#xff0c;欢迎指正&#xff0c;祝大家万事胜意&#xff01; 目录 前言 openGauss 数据库日志管理 1 实验介绍 2 实验目的 3 系统日志 3.1 运行时日志 3.2 安装卸载时日志…

gin源码分析(1)--初始化中间件,路由组与路由树

目标 关于gin.Default()&#xff0c;gin.New()&#xff0c;gin.Use()group与子group之间的关系&#xff0c;多group与middleware之间关系中间件的类型&#xff0c;全局&#xff0c;group&#xff0c;get&#xff0c;不同类型的中间件什么时候执行。中间件 next 和abort行为如何…

3款必知的AI写作软件,智能写文效率高

在当今信息爆炸的时代&#xff0c;写作已经成为人们生活和工作中不可或缺的一部分。然而&#xff0c;随着人们对高效率和高质量写作需求的不断增加&#xff0c;人工智能写作软件应运而生。这些AI写作软件凭借其强大的语言处理能力和智能算法&#xff0c;为写作者们提供了全新的…

郭天祥新概念51单片机(第四期读书笔记)

时钟周期、状态周期、机器周期、指令周期与晶振频率之间的关系 1、晶振频率与脉冲的关系 假设单片机的晶振频率是12MHz&#xff0c;那么它的一个脉冲为1/12微秒&#xff1b;晶振单位时间发出的脉冲则为&#xff1a; 12 ∗ 1 0 6 12*10^6 12∗106。 假设单片机的晶振频率是4MH…

LeetCode-240. 搜索二维矩阵 II【数组 二分查找 分治 矩阵】

LeetCode-240. 搜索二维矩阵 II【数组 二分查找 分治 矩阵】 题目描述&#xff1a;解题思路一&#xff1a;从左下角或者右上角元素出发&#xff0c;来寻找target。解题思路二&#xff1a;右上角元素&#xff0c;代码解题思路三&#xff1a;暴力也能过解题思路四&#xff1a;二分…

成都直播基地 天府新区产业园能获得哪些政府支持

为了推动成都直播产业的快速发展&#xff0c;政府出台了一系列政策措施&#xff0c;为成都直播基地提供了全方位的支持。本篇文章将为您具体解析入驻成都直播基地 天府新区产业园 天府锋巢直播产业基地都能获得哪些政府支持。 首先&#xff0c;天府新区作为成都市的重要发展区…