Medium
题目描述
给你一个整数数组 ranks ,表示一些机械工的能力值。ranks[i] 是第 i 位机械工的能力值。能力值为 r 的机械工可以在 r * n² 分钟内修好 n 辆车。
同时给你一个整数 cars ,表示总共需要修理的汽车数目。
请你返回修理所有汽车 最少 需要多少时间。
注意: 所有机械工可以同时修理汽车。
示例 1:
输入:ranks = [4,2,3,1], cars = 10
输出:16
解释:
- 第一位机械工修理 2 辆车,需要 4 * 2 * 2 = 16 分钟。
- 第二位机械工修理 2 辆车,需要 2 * 2 * 2 = 8 分钟。
- 第三位机械工修理 2 辆车,需要 3 * 2 * 2 = 12 分钟。
- 第四位机械工修理 4 辆车,需要 1 * 4 * 4 = 16 分钟。
可以证明无法在少于 16 分钟内修理完所有汽车。
示例 2:
输入:ranks = [5,1,8], cars = 6
输出:16
解释:
- 第一位机械工修理 1 辆车,需要 5 * 1 * 1 = 5 分钟。
- 第二位机械工修理 4 辆车,需要 1 * 4 * 4 = 16 分钟。
- 第三位机械工修理 1 辆车,需要 8 * 1 * 1 = 8 分钟。
可以证明无法在少于 16 分钟内修理完所有汽车。
提示:
1 <= ranks.length <= 10⁵1 <= ranks[i] <= 1001 <= cars <= 10⁶
解题思路
这是一道典型的二分查找答案题。我们需要找到修理所有汽车的最小时间。
核心思路:
观察规律:机械工能力值为
r,修理n辆车需要r * n²分钟。反过来,在给定时间t内,能力值为r的机械工最多可以修理⌊√(t/r)⌋辆车。二分查找:答案具有单调性 - 如果时间
t能修完所有车,那么任何大于t的时间也能修完。因此可以用二分查找最小的可行时间。判断可行性:对于给定时间
mid,计算所有机械工在该时间内最多能修理的汽车总数。如果总数 ≥cars,说明时间足够。边界确定:
- 左边界:0
- 右边界:最差情况下,能力最低的机械工修理所有车的时间,即
min_rank * cars²
算法步骤:
- 二分查找时间区间
[0, min_rank * cars²] - 对于中间值
mid,检查所有机械工在时间mid内能修理的汽车总数 - 根据总数与
cars的比较调整查找区间 - 返回找到的最小可行时间
推荐解法:二分查找 + 数学计算
代码实现
class Solution {
public:
long long repairCars(vector<int>& ranks, int cars) {
long long left = 0, right = (long long)(*min_element(ranks.begin(), ranks.end())) * cars * cars;
while (left < right) {
long long mid = left + (right - left) / 2;
long long totalCars = 0;
for (int rank : ranks) {
totalCars += (long long)sqrt(mid / rank);
}
if (totalCars >= cars) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};
class Solution:
def repairCars(self, ranks: List[int], cars: int) -> int:
left, right = 0, min(ranks) * cars * cars
while left < right:
mid = (left + right) // 2
total_cars = 0
for rank in ranks:
total_cars += int((mid // rank) ** 0.5)
if total_cars >= cars:
right = mid
else:
left = mid + 1
return left
public class Solution {
public long RepairCars(int[] ranks, int cars) {
long left = 0, right = (long)ranks.Min() * cars * cars;
while (left < right) {
long mid = left + (right - left) / 2;
long totalCars = 0;
foreach (int rank in ranks) {
totalCars += (long)Math.Sqrt(mid / rank);
}
if (totalCars >= cars) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}
var repairCars = function(ranks, cars) {
let left = 0, right = Math.min(...ranks) * cars * cars;
while (left < right) {
let mid = Math.floor((left + right) / 2);
let totalCars = 0;
for (let rank of ranks) {
totalCars += Math.floor(Math.sqrt(mid / rank));
}
if (totalCars >= cars) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n × log(min_rank × cars²)) | n 为机械工数量,二分查找需要 log(右边界) 次迭代,每次需要遍历所有机械工 |
| 空间复杂度 | O(1) | 只使用常数级额外空间 |
相关题目
. Sort Transformed Array (Medium)
. Koko Eating Bananas (Medium)