预算内的最多机器人数目
你有 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
解题思路
- 首先需要讲清楚:题目中提到的连续运行的机器人,是指连续的机器人,也就是子数组
首先我的思路是用双指针然后贪心,踢掉大的那一个,但是很显然局部最优解并不能得到正确答案
接着发现:双指针包含的数据越多,花费的时间也就越多,我们可以使用滑动窗口进行枚举,找到最大的机器人数为答案
接着需要注意的是我们要得到滑动窗口包含的chargeTimes的最大值以及runningCoasts的和
runningCoasts的和很好获取,在我们枚举右指针的时候加,在移动左指针的时候减
获取chargeTimes的最大值则使用一个单调队列 arr 进行存储,队列是递减的,在将要插入新数据的时候不断检查队尾的数据是否小于新数据,如果小于新数据,就将其弹出(注意尾要大于头),这样就维护了一个递减队列,队列的头就是滑动窗口中数据的最大值
接下来看看枚举的思路
首先用for循环枚举右指针,从0到最后
然后用while循环检查维护队列
然后向队列插入新数据
由于数据越多,时间就越多,所以当时间超过budget时,左指针就需要++了,所以用一个while循环检查时间是否超过budget,如果超过了,判断左指针的数据是否是此时数据的最大值,也就是是否与队列的头相等,如果相等,队列的头就需要++,将其弹出。然后记录数据的和的sum减去左指针指向的数。最后左指针++(注意左指针小于等于右指针)
最后就是不断判断时间小于等于budget的数据的长度,记录其中的最大值,返回即可
代码如下↓
int maximumRobots(int* chargeTimes, int chargeTimesSize, int* runningCosts, int runningCostsSize, long long budget) {
int l=0,r=0;
int res = 0;
int* arr = (int*)malloc(sizeof(int)*chargeTimesSize);
int h=0,t=0;
long long sum=0;
for(r=0;r<chargeTimesSize;r++)
{
sum+=runningCosts[r];
while(h<t && chargeTimes[r]>arr[t-1])
{
t--;
}//维护队列的单调递减性
arr[t] = chargeTimes[r];
t++;
while(l<=r && arr[h] + (r-l+1)*sum > budget)
{
if(chargeTimes[l] == arr[h])
{
h++;
}
sum-=runningCosts[l];
l++;
}
if(r-l+1>res)
{
res = r-l+1;
}
}
free(arr);
return res;
}