ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Maximum Number of Robots Within Budget

2022-09-04 22:02:19  阅读:175  来源: 互联网

标签:chargeTimes int runningCosts Within Robots long Budget len budget


Maximum Number of Robots Within Budget

You have $n$ robots. You are given two 0-indexed integer arrays, chargeTimes and runningCosts , both of length $n$. The i^{th} robot costs chargeTimes[i] units to charge and costs runningCosts[i] units to run. You are also given an integer budget .

The total cost of running $k$ chosen robots is equal to max(chargeTimes) + k * sum(runningCosts) , where max(chargeTimes) is the largest charge cost among the $k$ robots and sum(runningCosts) is the sum of running costs among the $k$ robots.

Return the maximum number of consecutive robots you can run such that the total cost does not exceed budget .

Example 1:

Input: chargeTimes = [3,6,1,3,4], runningCosts = [2,1,3,4,5], budget = 25
Output: 3
Explanation: 
It is possible to run all individual and consecutive pairs of robots within budget.
To obtain answer 3, consider the first 3 robots. The total cost will be max(3,6,1) + 3 * sum(2,1,3) = 6 + 3 * 6 = 24 which is less than 25.
It can be shown that it is not possible to run more than 3 consecutive robots within budget, so we return 3.

Example 2:

Input: chargeTimes = [11,12,19], runningCosts = [10,8,7], budget = 19
Output: 0
Explanation: No robot can be run that does not exceed the budget, so we return 0.

Constraints:

$chargeTimes.length == runningCosts.length == n$
$1 \leq n \leq 5 \times {10}^{4}$
$1 \leq chargeTimes[i], runningCosts[i] \leq {10}^{5}$
$1 \leq budget \leq {10}^{15}$

 

解题思路

  可以发现答案具有二段性,因此可以二分答案。假设最优解为长度为$ans$的区间,把这个区间右端点的元素去掉,可以发现区间最大值不会变大,而区间和变小(每个元素都是正整数),因此总代价减小。即如果最优解为$ans$,那么长度小于$ans$的区间也一定满足条件。因此具有二段性。

  然后在二分确定了区间长度后,每个区间的大小都是固定的,check函数就需要遍历所有长度相同的区间,并求每个区间的最大值和区间和,区间最值可以用单调队列来维护,区间和可以用一个变量来维护。

  AC代码如下,时间复杂度为$O(nlogn)$:

 1 class Solution {
 2 public:
 3     int n;
 4     long long m;
 5 
 6     bool check(int len, vector<int>& chargeTimes, vector<int>& runningCosts) {
 7         deque<int> q;
 8         long long s = 0;
 9         for (int i = 0; i < n; i++) {
10             // 维护区间最值
11             if (!q.empty() && i - q.front() + 1 > len) q.pop_front();
12             while (!q.empty() && chargeTimes[q.back()] <= chargeTimes[i]) {
13                 q.pop_back();
14             }
15             q.push_back(i);
16 
17             // 维护区间和
18             s += runningCosts[i];
19             if (i - len >= 0) s -= runningCosts[i - len];
20             
21             if (i - len + 1 >= 0 && chargeTimes[q.front()] + len * s <= m) return true;
22         }
23 
24         return false;
25     }
26 
27     int maximumRobots(vector<int>& chargeTimes, vector<int>& runningCosts, long long budget) {
28         n = chargeTimes.size();
29         m = budget;
30         
31         int l = 0, r = n;
32         while (l < r) {
33             int mid = l + r + 1 >> 1;
34             if (check(mid, chargeTimes, runningCosts)) l = mid;
35             else r = mid - 1;
36         }
37 
38         return l;
39     }
40 };

  还可以用双指针。定义指针$j$为当指针$i$固定后,满足条件的最左边的位置。当$i$往右边移动,$j$也应该往右边移动。假设$i$往右移动为$i'$,对应的最左边的位置为$j'$,且$j'$在$j$的左边,由于$j' \sim i'$这个区间满足要求,而$j' \sim i$也满足要求(前面二段性的证明),因此就与$j$为指针$i$最左边的位置矛盾了。

  AC代码如下,时间复杂度为$O(n)$:

 1 class Solution {
 2 public:
 3     int maximumRobots(vector<int>& chargeTimes, vector<int>& runningCosts, long long budget) {
 4         int n = chargeTimes.size();
 5         long long m = budget;
 6         
 7         deque<int> q;
 8         long long s = 0;
 9         int ret = 0;
10         for (int i = 0, j = 0; i < n; i++) {
11             s += runningCosts[i];
12             while (!q.empty() && chargeTimes[q.back()] <= chargeTimes[i]) {
13                 q.pop_back();
14             }
15             q.push_back(i);
16 
17             while (!q.empty() && chargeTimes[q.front()] + (i - j + 1) * s > m) {
18                 s -= runningCosts[j];
19                 if (q.front() == j) q.pop_front();
20                 j++;
21             }
22 
23             ret = max(ret, i - j + 1);
24         }
25 
26         return ret;
27     }
28 };

  最后扩展一下,题目要求的子序列是连续的,如果子序列可以不连续那应该怎么做呢?

  也是二分答案。先对所有机器人按照取最大值的那项 chargeTimes 按照从小到大的顺序排序,根据二分的值选出对应个数的机器人,假设是$len$个,枚举最大值选哪个,假设当前枚举到第$i$个,然后剩下的$len-1$个机器人一定是从排序后的第$i$个位置之前的机器人中选(如果从第$i$个位置后面选的话,那么最大值就不是第$i$个机器人了)。为了满足条件,应该从前面的机器人中选择$len-1$个最小的 runningCosts (总和应该尽可能小),这个可以用堆来维护。每次往堆插入一个元素,如果发现堆中的元素个数大于$k$,那么就把堆中最大的元素弹出。

  代码如下,时间复杂度为$O(n \cdot {log}^{2} n)$

 1 class Solution {
 2 public:
 3     int n;
 4     long long m;
 5     vector<int> idx;
 6 
 7     bool check(int len, vector<int>& chargeTimes, vector<int>& runningCosts) {
 8         priority_queue<int> pq;
 9         long long s = 0;
10         for (int i = 0; i < n; i++) {
11             if (pq.size() == len) {
12                 s -= pq.top();
13                 pq.pop();
14             }
15             pq.push(runningCosts[idx[i]]);
16             s += runningCosts[idx[i]];
17             if (pq.size() == len && chargeTimes[idx[i]] + len * s <= m) return true;
18         }
19 
20         return false;
21     }
22 
23     int maximumRobots(vector<int>& chargeTimes, vector<int>& runningCosts, long long budget) {
24         n = chargeTimes.size();
25         m = budget;
26 
27         for (int i = 0; i < n; i++) {
28             idx.push_back(i);
29         }
30         sort(idx.begin(), idx.end(), [&](int a, int b) {
31             return chargeTimes[a] < chargeTimes[b];
32         });
33 
34         int l = 0, r = n;
35         while (l < r) {
36             int mid = l + r + 1 >> 1;
37             if (check(mid, chargeTimes, runningCosts)) l = mid;
38             else r = mid - 1;
39         }
40 
41         return l;
42     }
43 };

 

参考资料

  力扣第86场双周赛:https://www.bilibili.com/video/BV11G41157DN

标签:chargeTimes,int,runningCosts,Within,Robots,long,Budget,len,budget
来源: https://www.cnblogs.com/onlyblues/p/16656219.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有