[LeetCode每日一题]2398. 预算内的最多机器人数目(使用deque维护数组中的最大值)

本文本质上为本人对力扣题解区灵茶山艾符的题解的理解.

这道题虽然是困难题,但没有难到离谱的地步,不要被困难吓到啦.

题目要求最多可以连续运行的机器人数目为多少,即求子数组问题,那我们依旧可以用滑动窗口来解决.而跟滑动窗口板子题相比,这道题对于开销的定义为max(chargeTimes) + k * sum(runningCosts)

sum(runningCosts)就可视作最基础的滑动窗口所维护的区间总值,那我们要解决的问题就变为了如何找到[left, right]区间中的max(chargeTimes).

    //入队
    while (!q.empty() && chargeTimes[right] >= chargeTimes[q.back()]) {
        q.pop_back();
    }
        q.push_back(right);
        sum += runningCosts[right];
    //出队
    while (!q.empty() && chargeTimes[q.front()] + (right - left + 1) * sum > budget) {
            if (left == q.front()) {
                q.pop_front();
            }
    }

​

运用deque(双端队列)可以很轻松的解决(如上述代码).在这段代码中,较难理解的就是入队部分.为什么比chargeTimes[right]小的队尾出队之后就不要入队了呢,这样难道不会影响right左边的值进而影响最大值吗.注意啦注意啦,我们要维护的只是max(chargeTimes),如果chargeTimes[right]是区间内的最大值的话,在现在right所在的位置变为区间的左端点之前,区间的最大值是不会小于chargeTimes[right]的,我们可以将这部分理解为一个单调栈.

再看出队,上述入队还可以用单调栈代替,我们没有必要用双端队列呀,别急,出队时就要用到这一点了.当出队影响max(chargeTimes)最大值的时候,就要从队头出列了.此时又诞生了一个疑问,我们的队列有没有可能是空的呢,这点大可不必担心,在right作为最大值清空队列成为队头后,我们将窗口右移,如果下一个比chargeTimes[right],我们依旧让他入队,换而言之,right只影响在right之前的值.

至此,我们已经解决了如何维护max(chargeTimes),问题迎刃而解.下面附上题解代码

class Solution {
public:
    int maximumRobots(vector<int>& chargeTimes, vector<int>& runningCosts, long long budget) {
        int res = 0, left = 0;
        long long sum = 0;
        deque<int> q;
        for (int right = 0; right < chargeTimes.size(); right++) {
            while (!q.empty() && chargeTimes[right] >= chargeTimes[q.back()]) {
                q.pop_back();
            }
            q.push_back(right);
            sum += runningCosts[right];

            while (!q.empty() && chargeTimes[q.front()] + (right - left + 1) * sum > budget) {
                if (left == q.front()) {
                    q.pop_front();
                }
                sum -= runningCosts[left];
                left++;
            }

            res = max(res, right - left + 1);
        }
        return res;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值