LeetCode:2398. 预算内的最多机器人数目 双指针+单调队列,时间复杂度O(n)

2398. 预算内的最多机器人数目

today 2398. 预算内的最多机器人数目

题目描述

你有 n 个机器人,给你两个下标从0开始的整数数组 chargeTimesrunningCosts ,两者长度都为 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
选择前 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*10^4
  • 1 <= chargeTimes[i], runningCosts[i] <= 10^5
  • 1 <= budget <= 10^15

题目解析

解题思路:双指针+单调队列。

我们首先可以使用双指针来维护一个窗口,窗口的左右边界分别为 leftright。 表示在leftright之间的机器人,可以正常运行。

如果leftright之间数值的和大于budget,我们需要缩小窗口,向右移动left,直到窗口内的机器人数目小于等于budget

同时,我们使用一个单调队列来维护窗口内机器人的chargeTimes 最大值。

遍历过程中right-left+1的最大值,即为最多可以连续运行的机器人数目。

单调队列实现方法:

  1. 维护一个单调递减的队列max_charge,初始为空。
  2. 对于每个新加入机器人对应的chargeTimechargeTimes[right],如果chargeTime大于队尾元素,则将队尾元素弹出直到队尾元素大于等于chargeTime,将chargeTime入队。这样保证了max_charge队列是单调递减的。
  3. max_charge队头元素,即为当前窗口内的最大充电时间。

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

代码实现

Python实现:

python 复制代码
from collections import deque

class Solution:
    def maximumRobots(self, chargeTimes, runningCosts, budget):
        n = len(chargeTimes)
        left = 0
        sum_running_cost = 0
        max_charge = deque()  # 单调队列,用于存储当前窗口内的最大充电时间
        res = 0
        
        for right in range(n):
            # 更新窗口内的运行成本总和
            sum_running_cost += runningCosts[right]
            
            # 维护单调队列,保证队列中的元素是递减的,以便快速获得窗口内最大充电时间
            while max_charge and chargeTimes[right] > max_charge[-1]:
                max_charge.pop()
            max_charge.append(chargeTimes[right])
            
            # 计算当前窗口的总开销
            while max_charge and max_charge[0] + (right - left + 1) * sum_running_cost > budget:
                # 如果超出预算,移动 left 缩小窗口,并更新相关值
                if chargeTimes[left] == max_charge[0]:
                    max_charge.popleft()
                sum_running_cost -= runningCosts[left]
                left += 1
            
            # 更新最大运行机器人数
            res = max(res, right - left + 1)
        
        return res

Go实现:

go 复制代码
func maximumRobots(chargeTimes []int, runningCosts []int, budget int64) int {
    n:=len(chargeTimes)
    left,right:=0,0
    sum_cost,ans:=0,0
    max_charge:=make([]int,0)
    for right=0;right<n;right++{
        //更新窗口内的运行成本总和
        sum_cost+=runningCosts[right]

        //维护单调队列,保证队列中的元素是递减的,以便快速获得窗口内最大充电时间
        for len(max_charge)>0 && max_charge[len(max_charge)-1]<chargeTimes[right]{
            max_charge=max_charge[:len(max_charge)-1]
        }
        max_charge=append(max_charge,chargeTimes[right])

        for left<=right && max_charge[0]+(right-left+1)*sum_cost>int(budget){
            //如果超出预算,移动 left 缩小窗口,并更新相关值
            if chargeTimes[left]==max_charge[0]{
                max_charge=max_charge[1:]
            }
            sum_cost-=runningCosts[left]
            left++
        }
        ans=max(ans,right-left+1)
        }
        return ans
    }

C++实现:

cpp 复制代码
class Solution {
public:
    int maximumRobots(vector<int>& chargeTimes, vector<int>& runningCosts, long long budget) {
        int n = chargeTimes.size();
        int left = 0;
        long long sum_cost = 0;
        int ans = 0;
        deque<int> max_charge;

        for (int right = 0; right < n; right++) {
            // 更新窗口内的运行成本总和
            sum_cost += runningCosts[right];

            // 维护单调队列,保证队列中的元素是递减的,以便快速获得窗口内最大充电时间
            while (!max_charge.empty() && max_charge.back() < chargeTimes[right]) {
                max_charge.pop_back();
            }
            max_charge.push_back(chargeTimes[right]);

            // 如果超出预算,移动 left 缩小窗口,并更新相关值
            while (left <= right && max_charge.front() + (right - left + 1) * sum_cost > budget) {
                if (chargeTimes[left] == max_charge.front()) {
                    max_charge.pop_front(); // 移除最大充电时间
                }
                sum_cost -= runningCosts[left];
                left++;
            }

            // 更新最大可运行的机器人数量
            ans = max(ans, right - left + 1);
        }

        return ans;
    }
};
相关推荐
linsa_pursuer1 分钟前
快乐数算法
算法·leetcode·职场和发展
小芒果_012 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
qq_434085904 分钟前
Day 52 || 739. 每日温度 、 496.下一个更大元素 I 、503.下一个更大元素II
算法
Beau_Will4 分钟前
ZISUOJ 2024算法基础公选课练习一(2)
算法
XuanRanDev7 分钟前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
gkdpjj8 分钟前
C++优选算法十 哈希表
c++·算法·散列表
代码猪猪傻瓜coding8 分钟前
力扣1 两数之和
数据结构·算法·leetcode
小码农<^_^>1 小时前
优选算法精品课--滑动窗口算法(一)
算法
羊小猪~~1 小时前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
道可云1 小时前
道可云人工智能&元宇宙每日资讯|2024国际虚拟现实创新大会将在青岛举办
大数据·人工智能·3d·机器人·ar·vr