leetcode
leetcode 2251 ~ 2300
修车的最少时间

修车的最少时间

难度:

标签:

题目描述

You are given an integer array ranks representing the ranks of some mechanics. ranksi is the rank of the ith mechanic. A mechanic with a rank r can repair n cars in r * n2 minutes.

You are also given an integer cars representing the total number of cars waiting in the garage to be repaired.

Return the minimum time taken to repair all the cars.

Note: All the mechanics can repair the cars simultaneously.

 

Example 1:

Input: ranks = [4,2,3,1], cars = 10
Output: 16
Explanation: 
- The first mechanic will repair two cars. The time required is 4 * 2 * 2 = 16 minutes.
- The second mechanic will repair two cars. The time required is 2 * 2 * 2 = 8 minutes.
- The third mechanic will repair two cars. The time required is 3 * 2 * 2 = 12 minutes.
- The fourth mechanic will repair four cars. The time required is 1 * 4 * 4 = 16 minutes.
It can be proved that the cars cannot be repaired in less than 16 minutes.​​​​​

Example 2:

Input: ranks = [5,1,8], cars = 6
Output: 16
Explanation: 
- The first mechanic will repair one car. The time required is 5 * 1 * 1 = 5 minutes.
- The second mechanic will repair four cars. The time required is 1 * 4 * 4 = 16 minutes.
- The third mechanic will repair one car. The time required is 8 * 1 * 1 = 8 minutes.
It can be proved that the cars cannot be repaired in less than 16 minutes.​​​​​

 

Constraints:

  • 1 <= ranks.length <= 105
  • 1 <= ranks[i] <= 100
  • 1 <= cars <= 106

代码结果

运行时间: 63 ms, 内存: 19.8 MB


/*
 * 思路:与普通Java方法类似,使用二分查找找到最小时间。唯一不同的是,使用Java Stream API来计算车的总数。
 */

import java.util.Arrays;

public class Solution {
    public int repairCars(int[] ranks, int cars) {
        int left = 1;
        int right = 100 * cars * cars;
        while (left < right) {
            int mid = (left + right) / 2;
            if (canRepairAllCars(ranks, cars, mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    private boolean canRepairAllCars(int[] ranks, int cars, int time) {
        return Arrays.stream(ranks)
                .mapToDouble(rank -> Math.sqrt(time / (double) rank))
                .sum() >= cars;
    }
}

解释

方法:

这个题解使用了二分搜索的方法来计算最少时间。首先,题目的目标是找到修理所有汽车的最少时间。时间是由机械工的能力值和他们修理的汽车数量决定的。二分搜索的范围设定为从0到最小能力值乘以汽车数的平方(即最坏情况下单个工人修所有车的时间)。在每次迭代中,通过检查当前中间值(mid)时间内是否可以修理完全部汽车来逐步缩小搜索范围。如果在给定的mid时间内所有机械工的总修车数达不到所需汽车数,说明需要更多时间,因此调整搜索范围的左边界。反之,则调整右边界。重复此过程直到找到最小的可行时间。

时间复杂度:

O(u * log(maxTime))

空间复杂度:

O(u)

代码细节讲解

🦆
为什么选择二分搜索作为解决这个问题的方法?
二分搜索是一种高效的搜索方法,适用于在有序的解空间中查找特定值。在这个问题中,最少时间是有序的,即如果在某个时间内能修完所有汽车,那么在更长的时间内也一定能修完。因此,通过二分搜索可以有效地缩小可能的时间范围,从而快速找到最小的符合条件的时间。这种方法比穷举所有可能的时间要高效得多。
🦆
在二分搜索中,如何确定右边界 `right = min(cnt) * cars * cars` 是合理的?
右边界 `right = min(cnt) * cars * cars` 是基于最坏情况来设定的,即假设最慢的工人(能力值最低)单独修理所有车辆所需要的最长时间。这个计算假设每个工人在完全不重叠的情况下独立完成修车任务。尽管这个估计很保守,但它确保了二分搜索的上界足够大,能包含实际的最小时间,从而保证搜索的完整性和正确性。
🦆
这种方法在极端情况下(例如所有工人能力值都相同或者极度不均匀)的表现如何?
在所有工人能力值相同的情况下,这种方法非常高效,因为所有工人的贡献相同,容易计算出每个时间点下的修车总量,从而快速缩小搜索范围找到最优解。在能力值极度不均匀的情况下,虽然会增加计算每个时间点的修车总量的复杂度,但二分搜索本身仍然有效,能够处理这种不均匀性,逐步逼近最小所需时间。尽管在计算过程中可能会有更多的迭代,但整体上仍然比直接计算每个可能时间要高效。

相关问题