C++二分向量算法:最多可以参加的会议数目 II

本题的其它解法

C++二分算法:最多可以参加的会议数目 II

本文涉及的基础知识点

二分查找算法合集

题目

给你一个 events 数组,其中 events[i] = [startDayi, endDayi, valuei] ,表示第 i 个会议在 startDayi 天开始,第 endDayi 天结束,如果你参加这个会议,你能得到价值 valuei 。同时给你一个整数 k 表示你能参加的最多会议数目。
你同一时间只能参加一个会议。如果你选择参加某个会议,那么你必须 完整 地参加完这个会议。会议结束日期是包含在会议内的,也就是说你不能同时参加一个开始日期与另一个结束日期相同的两个会议。
请你返回能得到的会议价值 最大和 。
示例 1:
输入:events = [[1,2,4],[3,4,3],[2,3,1]], k = 2
输出:7
解释:选择绿色的活动会议 0 和 1,得到总价值和为 4 + 3 = 7 。
示例 2:
输入:events = [[1,2,4],[3,4,3],[2,3,10]], k = 2
输出:10
解释:参加会议 2 ,得到价值和为 10 。
你没法再参加别的会议了,因为跟会议 2 有重叠。你 不 需要参加满 k 个会议。
示例 3:
输入:events = [[1,1,1],[2,2,2],[3,3,3],[4,4,4]], k = 3
输出:9
解释:尽管会议互不重叠,你只能参加 3 个会议,所以选择价值最大的 3 个会议。
**参数范围:
1 <= k <= events.length
1 <= k * events.length <= 106
1 <= startDayi <= endDayi <= 109
1 <= valuei <= 106

分析

时间复杂度

时间复杂度O(nlogn+knlogn)。第一步时间复杂度O(nlogn),第二步时间复杂度O(klongn)。
第一步:收集结束时间,排序并除去重复。并给每个结束时间安排索引。
第二步:两轮循环。

变量解释

vEndTime结束时间升序并除去重复元素
mEndTimeToIndexs结束时间在vEndTime中的顺序
vEndTimeIndexToMaxValuevEndTimeIndexToMaxValue[i]=j 表示,mEndTimeToIndexs[i]结束的会议的最大价值

注意

std::prev(it)之前不需要判断,因为vEndTime中插入了一个比任何开始时间都小的数0。
每轮循环后,要确保vEndTimeIndexToMaxValue升序。

代码

核心代码

class Solution {
public:int maxValue(vector<vector<int>>& events, int k) {vector<int> vEndTime = { 0 };for (const auto& v : events){vEndTime.emplace_back(v[1]);}sort(vEndTime.begin(), vEndTime.end());vEndTime.erase(std::unique(vEndTime.begin(), vEndTime.end()), vEndTime.end());unordered_map<int, int> mEndTimeToIndexs;for (int i = 0; i < vEndTime.size(); i++){mEndTimeToIndexs[vEndTime[i]] = i;}vector<int> vEndTimeIndexToMaxValue(vEndTime.size());while (k--){vector<int> dp(vEndTime.size());for (const auto& v : events){int iEndIndex = mEndTimeToIndexs[v[1]];auto it = std::lower_bound(vEndTime.begin(), vEndTime.end(), v[0]);const int iMaxPreIndex = it - 1 - vEndTime.begin() ;const int iMaxValue = vEndTimeIndexToMaxValue[iMaxPreIndex] + v[2];dp[iEndIndex] = max(dp[iEndIndex],iMaxValue);}//使得dp升序int iPreMax = 0;for (auto& n : dp){n = max(n, iPreMax);iPreMax = max(n, iPreMax);}dp.swap(vEndTimeIndexToMaxValue);}return vEndTimeIndexToMaxValue.back();}
};

测试用例

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}

template
void Assert(const vector& v1, const vector& 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<vector> events;
int k;
int res;
{
Solution slu;
events = { {1,2,4},{3,4,3},{2,3,1} };
k = 2;
res = slu.maxValue(events, k);
Assert(res,7 );
}
{
Solution slu;
events = { {1,2,4},{3,4,3},{2,3,10} };
k = 2;
res = slu.maxValue(events, k);
Assert(res, 10);
}
{
Solution slu;
events = { {1,1,1},{2,2,2},{3,3,3},{4,4,4} };
k = 3;
res = slu.maxValue(events, k);
Assert(res, 9);
}

//CConsole::Out(res);

}

优化

代码

class Solution {
public:int maxValue(vector<vector<int>>& events, int k) {vector<int> vEndTime = { 0 };for (const auto& v : events){vEndTime.emplace_back(v[1]);}sort(vEndTime.begin(), vEndTime.end());vEndTime.erase(std::unique(vEndTime.begin(), vEndTime.end()), vEndTime.end());unordered_map<int, int> mEndTimeToIndexs;for (int i = 0; i < vEndTime.size(); i++){mEndTimeToIndexs[vEndTime[i]] = i;}sort(events.begin(), events.end(), [](const auto& v0, const auto& v1) {return v0[0] < v1[0]; });vector<int> vEndTimeIndexToMaxValue(vEndTime.size());while (k--){vector<int> dp(vEndTime.size());int iPreMax = 0;int iPreIndex = 0;for (const auto& v : events){while ((iPreIndex < vEndTimeIndexToMaxValue.size()) && (vEndTime[iPreIndex] < v[0])){iPreMax = max(iPreMax, vEndTimeIndexToMaxValue[iPreIndex]);iPreIndex++;}int iEndIndex = mEndTimeToIndexs[v[1]];dp[iEndIndex] = max(dp[iEndIndex], iPreMax+v[2]);}dp.swap(vEndTimeIndexToMaxValue);			}return *std::max_element(vEndTimeIndexToMaxValue.begin(), vEndTimeIndexToMaxValue.end());}
};

时间复杂度

O(nk)

分析

将events通过开始时间排序后,就可以使用离线查询。

sort(events.begin(), events.end(), [](const auto& v0, const auto& v1) {return v0[0] < v1[0]; });

iPreMax 记录了所有结束时间比当前时间小的最大会议价值的最大值。

vEndTimeIndexToMaxValue[0,iPreIndex)的会议价值已经更新到iPreMax。 
while ((iPreIndex < vEndTimeIndexToMaxValue.size()) && (vEndTime[iPreIndex] < v[0])){iPreMax = max(iPreMax, vEndTimeIndexToMaxValue[iPreIndex]);iPreIndex++;}

注意: vEndTimeIndexToMaxValue不再升序,所以要:

return *std::max_element(vEndTimeIndexToMaxValue.begin(), vEndTimeIndexToMaxValue.end());

优化二:从开始时间大的处理

代码

class Solution {
public:int maxValue(vector<vector<int>>& events, int k) {vector<int> vEndTime = { 0 };for (const auto& v : events){vEndTime.emplace_back(v[1]);}sort(vEndTime.begin(), vEndTime.end());vEndTime.erase(std::unique(vEndTime.begin(), vEndTime.end()), vEndTime.end());unordered_map<int, int> mEndTimeToIndexs;for (int i = 0; i < vEndTime.size(); i++){mEndTimeToIndexs[vEndTime[i]] = i;}sort(events.begin(), events.end(), [](const auto& v0, const auto& v1) {return v0[0] > v1[0]; });vector<int> vEndTimeIndexToMaxValue(vEndTime.size());while (k--){int iPreIndex = vEndTimeIndexToMaxValue.size()-1 ;for (const auto& v : events){while ((iPreIndex >=0 ) && (vEndTime[iPreIndex] >= v[0])){	iPreIndex--;}int iEndIndex = mEndTimeToIndexs[v[1]];vEndTimeIndexToMaxValue[iEndIndex] = max(vEndTimeIndexToMaxValue[iEndIndex], vEndTimeIndexToMaxValue[iPreIndex] +v[2]);}//使得dp升序int iPreMax = 0;for (auto& n : vEndTimeIndexToMaxValue){n = max(n, iPreMax);iPreMax = max(n, iPreMax);}}return *std::max_element(vEndTimeIndexToMaxValue.begin(), vEndTimeIndexToMaxValue.end());}
};

分析

时间复杂度O(kn)。

优点

不需要滚动向量,因为更新结束时间大的不会影响开始时间小的。

注意

一,开始时间降序排序。

 {return v0[0] > v1[0]; });

二,vEndTimeIndexToMaxValue必须保持升序。

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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

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

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

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

相关文章

gitt开源项目的意义,公司为什么会对在gitt上有开源项目的人更大机会

Git是一种分布式版本控制系统&#xff0c;它可以帮助程序员管理代码的历史版本和协同工作。同时&#xff0c;Git也成为了开源项目的主要托管平台之一。Git的开源项目意义重大&#xff0c;因为这种开源项目托管平台可以帮助开发者将代码和项目分享给全球的开发者&#xff0c;并且…

从0开始学习JavaScript--JavaScript元编程

JavaScript作为一门灵活的动态语言&#xff0c;具备强大的元编程能力。元编程是一种通过操作程序自身结构的编程方式&#xff0c;使得程序能够在运行时动态地创建、修改、查询自身的结构和行为。本文将深入探讨JavaScript中元编程的各个方面&#xff0c;包括原型、反射、代理等…

2023亚太杯数学建模C题思路模型代码

已完成C题思路代码&#xff0c;文末名片获取 C题是我们的一个数据分析问题&#xff0c;这个题目主要就是我们要去收集数据&#xff0c;清洗处理后进行分析。 问题1&#xff1a;分析影响中国新能源电动汽车发展的主要因素&#xff0c;建立数学模型&#xff0c;描述这些因素对中…

对未来新能源车测试工具的看法

汽车行业正在经历变革的说法算是比较轻描淡写的了&#xff0c;还记得我1983年加入这个行业时&#xff0c;行业聚焦点是引入发动机管理系统。当时还是以家庭掀背车为主的时代&#xff0c;发动机分析仪的体积像衣柜一样大&#xff0c;还没出现“CAN”通信协议。现在经常听到我的导…

PHP预约上门回收废品系统的代码披露

PHP预约上门回收废品系统的代码披露 <?phpnamespace app\admin\controller;class Code {public function getTopDomainhuo(){error_reporting(0);$host $_SERVER["HTTP_HOST"];$matchstr "[^\\.]\\.(?:(" . $host . ")|\\w{2}|((" . $ho…

【第一部分:概述】ARM Realm Management Monitor specification

目录 概述机密计算系统软件组成MonitorRealmRealm Management Monitor (RMM)Virtual Machine (VM)HypervisorSecure Partition Manager (SPM)Trusted OS (TOS)Trusted Application (TA) Realm Management Monitor 参考文献 概述 RMM是一个软件组件&#xff0c;它构成了实现ARM…

机器学习笔记 - 复杂任务的CNN组合

基础CNN架构可通过多种方式进行组合和扩展,从而解决更多、更复杂的任务。 1. 分类和定位 在分类和定位任务中,你不仅需要说出在图像中找到的物体的类别,而且还需指出物体显现在图像中的边界框坐标。这类任务假设在图像中只有一个物体实例。 这个任务可通过在典型的分类网络…

每日一题(LeetCode)----链表--两数相加

每日一题(LeetCode)----链表–两数相加 1.题目&#xff08;2. 两数相加&#xff09; 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返…

深入ReentrantReadWriteLock(一)

一、为什么要出现读写锁 synchronized和ReentrantLock都是互斥锁。 如果说有一个操作是读多写少的&#xff0c;还要保证线程安全的话。如果采用上述的两种互斥锁&#xff0c;效率方面很定是很低的。 在这种情况下&#xff0c;咱们就可以使用ReentrantReadWriteLock读写锁去实现…

React16中打印事件对象取不到值的现象及其原因分析

React16中打印事件对象取不到值的现象及其原因分析 一、背景 在最近的开发过程中&#xff0c;遇到了一个看起来匪夷所思的问题❓&#xff1a; <Inputplaceholder"请输入"onChange{(e) > {console.log(e:, e)}}onKeyDown{handleKeyDown} />此时按理来说我…

旅行商问题(枚举,回溯,动态规划,贪心,分支界限)

文章目录 问题描述暴力枚举回溯法动态规划法贪心法分支界限法 问题描述 假设有一个货郎担要拜访n个城市&#xff0c;他必须选择所要走的路程&#xff0c;路程的限制时每个城市只能拜访一次&#xff0c;而且最后要走到原来出发的城市&#xff0c;要求路径长度。 旅行商问题将要…

为销售赋能:利用 Splashtop 增强远程培训技术

远程销售团队这一概念在当今快节奏的商业环境中日益普遍。各公司正在计划在不同地点灵活开展销售业务&#xff0c;希望利用技术优势缩小地域差距。但是&#xff0c;这种向远程销售的转型面临着重大挑战&#xff0c;尤其在培训和发展领域。培训远程销售团队需要采用创新方法&…

常见树种(贵州省):012茶、花椒、八角、肉桂、杜仲、厚朴、枸杞、忍冬

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、茶 灌…

鸿蒙 ark ui 轮播图实现教程

前言&#xff1a; 各位同学有段时间没有见面 因为一直很忙所以就没有去更新博客。最近有在学习这个鸿蒙的ark ui开发 因为鸿蒙不是发布了一个鸿蒙next的测试版本 明年会启动纯血鸿蒙应用 所以我就想提前给大家写一些博客文章 效果图 具体实现 我们在鸿蒙的ark ui 里面列表使…

土地利用数据技术服务

一、背景介绍 土地是人类赖以生存与发展的重要资源和物质保障&#xff0c;在“人口&#xff0d;资源&#xff0d;环境&#xff0d;发展&#xff08;PRED&#xff09;”复合系统 中&#xff0c;土地资源处于基础地位。随着现代社会人口的不断增长以及工业化、城市化进程的加速&a…

Excel使用VLOOKUP查询数据

VLOOKUP函数在百度百科中的解释是&#xff1a; 解释一下&#xff0c;函数需要4个参数&#xff1a; 参数1&#xff08;lookup_value&#xff09;&#xff1a;需要匹配的值参数2&#xff08;table_array&#xff09;&#xff1a;在哪个区域里进行匹配参数3&#xff08;col_index…

Dubbo3使用Zookeeper作为注册中心的方案讨论!详解DubboAdmin与PrettyZoo来监控服务的优劣!

文章目录 一&#xff1a;Dubbo注册中心的基本使用 二&#xff1a;Zookeeper注册中心的使用 1&#xff1a;依赖引入 2&#xff1a;实际开发 三&#xff1a;Zookeeper作为注册中心的使用展示 1&#xff1a;启动注册Zookeeper服务 2&#xff1a;引入注册中心 (一)&#xf…

Java 21增强对Emoji表情符号的处理了

现一个 Java 21 中有意思的东西&#xff01; 在java.Lang.Character类中增加了用于确定字符是否为 Emoji 表情符号的 API&#xff0c;主要包含下面六个新的静态方法&#xff1a; public static boolean isEmoji(int codePoint) {return CharacterData.of(codePoint).isEmoji(…

操作系统 day13(RR、优先级调度)

RR&#xff08;时间片轮转&#xff09; 响应时间&#xff1a;系统中有10个进程正在并发执行&#xff0c;如果时间片为1秒&#xff0c;则一个进程被响应可能需要等待9秒。也就是说&#xff0c;如果用户在自己进程的时间片外通过键盘发出调试命令&#xff0c;可能需要等待9秒才能…