Maximum Number of Robots Within Budget
Maximum Number of Robots Within Budget
You have robots. You are given two 0-indexed integer arrays, chargeTimes and runningCosts , both of length . 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 chosen robots is equal to max(chargeTimes) + k * sum(runningCosts) , where max(chargeTimes) is the largest charge cost among the robots and sum(runningCosts) is the sum of running costs among the 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}$
解题思路
可以发现答案具有二段性,因此可以二分答案。假设最优解为长度为的区间,把这个区间右端点的元素去掉,可以发现区间最大值不会变大,而区间和变小(每个元素都是正整数),因此总代价减小。即如果最优解为,那么长度小于的区间也一定满足条件。因此具有二段性。
然后在二分确定了区间长度后,每个区间的大小都是固定的,check函数就需要遍历所有长度相同的区间,并求每个区间的最大值和区间和,区间最值可以用单调队列来维护,区间和可以用一个变量来维护。
AC代码如下,时间复杂度为:
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 };
还可以用双指针。定义指针为当指针固定后,满足条件的最左边的位置。当往右边移动,也应该往右边移动。假设往右移动为,对应的最左边的位置为,且在的左边,由于这个区间满足要求,而也满足要求(前面二段性的证明),因此就与为指针最左边的位置矛盾了。
AC代码如下,时间复杂度为:
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 按照从小到大的顺序排序,根据二分的值选出对应个数的机器人,假设是个,枚举最大值选哪个,假设当前枚举到第个,然后剩下的个机器人一定是从排序后的第个位置之前的机器人中选(如果从第个位置后面选的话,那么最大值就不是第个机器人了)。为了满足条件,应该从前面的机器人中选择个最小的 runningCosts (总和应该尽可能小),这个可以用堆来维护。每次往堆插入一个元素,如果发现堆中的元素个数大于,那么就把堆中最大的元素弹出。
代码如下,时间复杂度为:
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
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16656219.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效