C++前缀和算法的应用:预算内的最多机器人数目

2023-10-28 12:20

本文主要是介绍C++前缀和算法的应用:预算内的最多机器人数目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频
单调双向队列
滑动窗口

题目

你有 n 个机器人,给你两个下标从 0 开始的整数数组 chargeTimes 和 runningCosts ,两者长度都为 n 。第 i 个机器人充电时间为 chargeTimes[i] 单位时间,花费 runningCosts[i] 单位时间运行。再给你一个整数 budget 。
运行 k 个机器人 总开销 是 max(chargeTimes) + k * sum(runningCosts) ,其中 max(chargeTimes) 是这 k 个机器人中最大充电时间,sum(runningCosts) 是这 k 个机器人的运行时间之和。
请你返回在 不超过 budget 的前提下,你 最多 可以 连续 运行的机器人数目为多少。
示例 1:
输入:chargeTimes = [3,6,1,3,4], runningCosts = [2,1,3,4,5], budget = 25
输出:3
解释:
可以在 budget 以内运行所有单个机器人或者连续运行 2 个机器人。
选择前 3 个机器人,可以得到答案最大值 3 。总开销是 max(3,6,1) + 3 * sum(2,1,3) = 6 + 3 * 6 = 24 ,小于 25 。
可以看出无法在 budget 以内连续运行超过 3 个机器人,所以我们返回 3 。
示例 2:
输入:chargeTimes = [11,12,19], runningCosts = [10,8,7], budget = 19
输出:0
解释:即使运行任何一个单个机器人,还是会超出 budget,所以我们返回 0 。
参数范围
chargeTimes.length == runningCosts.length == n
1 <= n <= 5 * 104
1 <= chargeTimes[i], runningCosts[i] <= 105
1 <= budget <= 1015

分析

时间复杂度

两层循环,但第二层循环,没有从头开始。所以总时间复杂度是O(n)。

滑动窗口

[left,r)如果r增加,则预算也增加。对于每个left,我们求出使[left,r]超过预算的第一个r,也就是[left,r)以left开始可以运行最多的连续机器人。这是滑动窗口的经典应用场景。

求最大充电时间(单调双向队列)

对于任意连续机器人[left,r),如果left <= x1 < x2 < r ,且chargeTimes[x1] <= chargeTimes[x2],则chargeTimes[x1]被 chargeTimes[x2]淘汰了。双向队列依qIndex次记录除淘汰外的x,那么qIndex对应的值是递减的,这意味者首元素对应的值就是最大值。qIndex会在以下情况被修改:

x2淘汰x1
增加x2
移除left,left可能已经被淘汰
[left,r]超过预算时:应该从队列移除r,不移除也可以,下个left会移除的。

注意:

r不能小于left,所以在枚举left结束时,根据需要看是否要增加r。

大致步骤

一,求前缀和。
二,枚举left。
a,枚举r。
b,更新iRet(返回值)。
c,更新双向队列。
d,如果需要更新r。
e,更新left。

枚举r退出循环

有两种情况退出循环。

方式一r=m_c,越界。[left,r)一定没超过预算,否则以方式二,退出了。
方式二[left,r]超出预算。[left,r)一定没超过预算,否则上一轮循环就退出了。
总结两种退出方式,[left,r)都是以left开始的最长连续机器人。

代码

核心代码

class Solution {
public:
int maximumRobots(vector& chargeTimes, vector& runningCosts, long long budget) {
m_c = chargeTimes.size();
vector vSum = { 0 };
for (const auto& n : runningCosts)
{
vSum.emplace_back(n + vSum.back());
}
int right = 0;
std::deque qIndexs;
int iRet = 0;
for (int left = 0; left < m_c; left++)
{
//枚举r
while (right < m_c)
{
while (qIndexs.size() && (chargeTimes[qIndexs.back()] <= chargeTimes[right]))
{
qIndexs.pop_back();
}
qIndexs.emplace_back(right);
//计算[left,right+1)的积分
const long long curCost = chargeTimes[qIndexs.front()]+(right + 1 -left)* (vSum[right+1]-vSum[left]);
if (curCost > budget)
{
break;
}
right++;
}
iRet = max(iRet, right - left);
//滑动窗口中删除left
if (qIndexs.size()&&(qIndexs.front() == left))
{
qIndexs.pop_front();
}
if (right <= left)
{
right++;
}
}
return iRet;
}
int m_c;
};

测试用例

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]);
}
}

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

int main()
{
Solution slu;
vector chargeTimes, runningCosts;
long long budget = 0;
int res;
chargeTimes = { 19,63,21,8,5,46,56,45,54,30,92,63,31,71,87,94,67,8,19,89,79,25 };
runningCosts = { 91,92,39,89,62,81,33,99,28,99,86,19,5,6,19,94,65,86,17,10,8,42 };
budget = 85;
res = slu.maximumRobots(chargeTimes, runningCosts, budget);
Assert(1 ,res);
chargeTimes = { 3, 6, 1, 3, 4 };
runningCosts = { 2, 1, 3, 4, 5 };
budget = 25;
res = slu.maximumRobots(chargeTimes, runningCosts, budget);
Assert(3, res);

//CConsole::Out(res);

}

2023年3月旧代码

class Solution {
public:
int maximumRobots(vector& chargeTimes, vector& runningCosts, long long budget) {
m_c = chargeTimes.size();
int left = 0;
int iRet = 0;
vector vSum(1);
std::deque qMaxIndexs;
for (int r = 0; r < m_c; r++)
{
vSum.push_back(vSum.back() + runningCosts[r]);
while (qMaxIndexs.size() && chargeTimes[r] >= chargeTimes[qMaxIndexs.back()])
{
qMaxIndexs.pop_back();
}
qMaxIndexs.push_back®;
while (qMaxIndexs.size() && ((vSum[r + 1] - vSum[left])*(r - left + 1) + chargeTimes[qMaxIndexs.front()] > budget))
{
if (qMaxIndexs.front() == left)
{
qMaxIndexs.pop_front();
}
left++;
}
iRet = max(iRet, r - left + 1);
}
return iRet;
}
int m_c;
};

2023年9月旧代码

class Solution {
public:
int maximumRobots(vector& chargeTimes, vector& runningCosts, long long budget) {
std::deque que;
int iRet = -1;
long long sum = 0;
for (int left = 0, r = 0; left < chargeTimes.size(); left++)
{
while (que.size() && (que.front() < left ))
{
que.pop_front();
}
for (; r < chargeTimes.size(); r++)
{
while (que.size() && (chargeTimes[que.back()] <= chargeTimes[r]))
{
que.pop_back();
}
que.emplace_back®;
const long long curNeed = (sum+ runningCosts[r])*(r-left+1) + chargeTimes[que.front()];
if (curNeed > budget)
{
break;
}
sum += runningCosts[r];
}
iRet = max(iRet, r - left );
//sum是runningCosts[left…r)的和
if (left != r)
{
sum -= runningCosts[left];
}
else
{
r++;
}
}
return iRet;
}
};

扩展阅读

视频课程

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

相关文章

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Java中&和&&以及|和||的区别、应用场景和代码示例

《Java中&和&&以及|和||的区别、应用场景和代码示例》:本文主要介绍Java中的逻辑运算符&、&&、|和||的区别,包括它们在布尔和整数类型上的应用,文中通过代码介绍的非常详细,需要的朋友可... 目录前言1. & 和 &&代码示例2. | 和 ||代码示例3. 为什么要使用 & 和 | 而不是总是使

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa