目录
2594. 修车的最少时间 - (LeetCode)
题目描述:
给你一个整数数组 ranks
,表示一些机械工的 能力值 。ranksi
是第 i
位机械工的能力值。能力值为 r
的机械工可以在 r * n2
分钟内修好 n
辆车。
同时给你一个整数 cars
,表示总共需要修理的汽车数目。
请你返回修理所有汽车 最少 需要多少时间。
注意:所有机械工可以同时修理汽车。
样例:
输入: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 分钟是修理完所有车需要的最少时间。
思路解析
首先,我们观察到的一个任务的完成时间是所有修车厂完成时间的最大值。使用数学语言表达就是 time = max{r_i * n_i ^ 2}。而这道问题就是让我们求取 min{time}。所以这是一道最小化最大值的题型。所以,我们可以使用二分答案 -- 二分查找。
明确算法之后,我们来判定二分什么?二分的核心在于求值转变为判定。同时,此时二分的区域是答案 -- 值域,所以的判定的位置在与其他位置。关注到定义域为 n 的范围, 表达式 time_i = r_i * n_i ^ 2,且 ∑n_i = cars。所以,我们可以知道 n_i = sqrt(time_i / r_i)。显然 n_i 与 time_i 是正相关关系。所以当 ∑n_i >= cars 时,必有 time_i >= time。其中 time 是所求的答案。
AC代码
class Solution {
bool check(vector<int>& ranks, long long times, long long cars) {
long long tot = 0;
for (int i = 0; i < ranks.size(); ++i) {
tot += (long long) (sqrt(times / ranks[i])); // 需要向下取整,因为车辆数需要是整数
}
return tot >= cars;
}
public:
long long repairCars(vector<int>& ranks, int cars) {
long long begin = 1, end = 10e15; // 查询足够大的范围即可
while (begin < end) {
long long mid = begin + (end - begin >> 1);
if (check(ranks, mid, cars)) {
end = mid;
} // time_i >= time
else {
begin = mid + 1;
} // time_i < time
} // 二分答案 -- lower_bound为模板
return begin; // time_i == time
}
};