💻 同时运行 N 台电脑的最长时间
📝 题目描述
你有n
台电脑。给你整数n
和一个下标从0开始的整数数组batteries
,其中第i
个电池可以让一台电脑运行batteries[i]
分钟。你想使用这些电池让全部n
台电脑同时运行。
一开始,你可以给每台电脑连接至多一个电池。然后在任意整数时刻,你都可以将一台电脑与它的电池断开连接,并连接另一个电池,你可以进行这个操作任意次。新连接的电池可以是一个全新的电池,也可以是别的电脑用过的电池。断开连接和连接新的电池不会花费任何时间。
注意,你不能给电池充电。
请你返回你可以让n
台电脑同时运行的最长分钟数。
📋 代码模板
class Solution {
public long maxRunTime(int n, int[] batteries) {
}
}
function maxRunTime(n: number, batteries: number[]): number {
}
💡 提示
🚀 示例
示例一
输入为n = 2, batteries = [3,3,3]
,输出为4
,方案如下。
- 一开始,将第一台电脑与电池①连接,第二台电脑与电池②连接。
分钟后,将第二台电脑与电池②断开连接,并连接电池③,此时电池②还可供电 分钟。 分钟后,将第一台电脑与电池①断开连接,并连接电池②,此时电池①已被耗尽,电池③还可供电 分钟。 分钟后,电池①被耗尽,只剩余电池③可供电 分钟,已无法再使两台电脑同时运行。
示例二
输入为n = 2, batteries = [1,1,1,1]
,输出为2
,方案如下。
- 一开始,将第一台电脑与电池①连接,第二台电脑与电池③连接。
分钟后,将第一台电脑与电池①断开连接,并连接电池②。同时,将第二台电脑与电池③断开连接,并连接电池④。此时电池①和③已被耗尽。 分钟后,电池②和④也被耗尽,无剩余电池可供电,已无法再使两台电脑同时运行。
🖊️ 题解
假设
二分查找的下限可以设置为
那么我们如何来验证所有电脑是否能够同时运行
设
为 , 为 , 为 ,验证这 台电脑能否同时运行 分钟。 要使
台电脑同时运行 分钟,需要 格电量,我们可以把它类比为一个 的网格,每个单元格为所需的一格电量。
- 我们把不同电池的电量用不同颜色进行标记,从每块电池选取
格电量,共 格电量。
- 按颜色交替地列式涂色
的网格,若能涂色满,则说明 台电脑能够同时运行 分钟,否则 台电脑不能够同时运行 分钟。因此,将网格涂满色的条件为 ,也是 函数为真的条件。其中,每一行代表一分钟。
- 题目要求同一块电池在同一分钟内只能被一台电脑使用,即说明一行中的单元格不能出现相同涂色,那上述涂色法就一定能够保证这一点成立呢?答案是能够保证,因为一列上的单元格数量为
,在这种涂色方案下,对于任意一个涂色的单元格,如果要在其所在行上出现相同的涂色,颜色的数量至少需要 个,而一个相同的颜色的选择数量最大为 ,所以在同一行上不可能出现相同的涂色。
class Solution {
public long maxRunTime(int n, int[] batteries) {
long total = 0;
for (int battery : batteries) {
total += battery;
}
long low = 1, high = total / n;
while (low <= high) {
long mid = low + ((high - low) >> 1);
if (check(n, batteries, mid)) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return high;
}
private boolean check(int n, int[] batteries, long t) {
long sum = 0;
for (int battery : batteries) {
sum += Math.min(battery, t);
}
return n * t <= sum;
}
}
function maxRunTime(n: number, batteries: number[]): number {
const check = (t: number): boolean => {
let sum = 0;
for (const battery of batteries) {
sum += Math.min(battery, t);
}
return n * t <= sum;
}
let low = 1, high = Math.floor(batteries.reduce((acc, cur) => acc + cur, 0) / n);
while (low <= high) {
const mid = low + Math.floor((high - low) / 2);
if (check(mid)) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return high;
}
💭 复杂度分析
基于二分查找
的解决方案的复杂度分析如下。
- 时间复杂度:
,其中 为二分查找的上下限之差, 为数组 长度。 - 空间复杂度:
。