day122—二分查找—完成旅途的最少时间(LeetCode-2187)

题目描述

给你一个数组 time ,其中 time[i] 表示第 i 辆公交车完成 一趟 旅途 所需要花费的时间。

每辆公交车可以 连续 完成多趟旅途,也就是说,一辆公交车当前旅途完成后,可以 立马开始 下一趟旅途。每辆公交车 独立 运行,也就是说可以同时有多辆公交车在运行且互不影响。

给你一个整数 totalTrips ,表示所有公交车 总共 需要完成的旅途数目。请你返回完成 至少 totalTrips 趟旅途需要花费的 最少 时间。

示例 1:

复制代码
输入:time = [1,2,3], totalTrips = 5
输出:3
解释:
- 时刻 t = 1 ,每辆公交车完成的旅途数分别为 [1,0,0] 。
  已完成的总旅途数为 1 + 0 + 0 = 1 。
- 时刻 t = 2 ,每辆公交车完成的旅途数分别为 [2,1,0] 。
  已完成的总旅途数为 2 + 1 + 0 = 3 。
- 时刻 t = 3 ,每辆公交车完成的旅途数分别为 [3,1,1] 。
  已完成的总旅途数为 3 + 1 + 1 = 5 。
所以总共完成至少 5 趟旅途的最少时间为 3 。

示例 2:

复制代码
输入:time = [2], totalTrips = 1
输出:2
解释:
只有一辆公交车,它将在时刻 t = 2 完成第一趟旅途。
所以完成 1 趟旅途的最少时间为 2 。

提示:

  • 1 <= time.length <= 105
  • 1 <= time[i], totalTrips <= 107

解决方案:

算法目标

给定多辆车的单趟完成时间和需要完成的总趟数,找出完成所有趟数所需的最少时间

核心思路

  1. 确定时间范围 :时间在[0, 最慢车×总趟数]之间

  2. 二分查找时间:尝试不同的时间,计算在该时间内能完成多少趟

  3. 寻找最小值:找到能满足总趟数要求的最小时间

算法步骤

1. 确定查找范围

复制代码
int min_tmp = *min_element(time.begin(), time.end());
long long left = -1;  // 不可行的下界
long long right = (long long)min_tmp * totalTrips;  // 可行的上界
  • 下界:-1(肯定不够的时间)

  • 上界:用最慢的车完成所有趟数的时间

  • 使用开区间(left, right)left永远不可行,right永远可行

2. 二分查找主循环

复制代码
while(left + 1 < right) {
    long long mid = left + (right - left) / 2;  // 尝试的时间
    // 计算在时间mid内能完成的趟数
    // 判断并更新边界
}

3. 计算可完成趟数

复制代码
long long tmp = 0;
for(auto p : time) {
    tmp += mid / p;  // 每辆车在时间mid内能完成的趟数
    if(tmp >= totalTrips) break;  // 提前退出优化
}
  • 对每辆车:在时间mid内能完成mid / time[i]

  • 累加所有车的趟数

  • 提前退出:当已满足总趟数要求时停止计算

4. 判断并更新边界

if(tmp < totalTrips) {

left = mid; // 时间不够,需要更多时间

} else {

right = mid; // 时间足够,尝试更少时间

}

5. 返回结果

return right; // 最小的可行时间

关键点

  • 二分查找对象 :总时间t,不是车辆数

  • 验证条件 :在时间t内能完成的趟数≥ totalTrips

  • 搜索方向 :寻找满足条件的最小t

  • 整数除法mid / p自动向下取整,因为一趟必须完整完成

时间复杂度

  • 寻找最慢车:O(n)

  • 二分查找:O(log(min_time × totalTrips))

  • 每次验证:O(n)

  • 总时间:O(n log T)

示例

复制代码
time = [1, 2, 3]
totalTrips = 5

查找过程:
1. 范围: t ∈ [0, 1×5=5]
2. 尝试 t=2: 可完成3趟 < 5 → 不够
3. 尝试 t=3: 可完成5趟 ≥ 5 → 足够
4. 最终结果: t=3

算法正确性

  • 单调性:时间越长,能完成的趟数越多

  • 边界保证:left永远不可行,right永远可行

  • 最终right是最小的可行时间

优化亮点

  1. 提前退出:当趟数已达标时立即停止计算

  2. 开区间二分:避免边界处理复杂

  3. 类型安全 :使用long long防止溢出

函数源码:

cpp 复制代码
class Solution {
public:
    long long minimumTime(vector<int>& time, int totalTrips) {
        int min_tmp=time[0];
        for(auto p:time){
            min_tmp=min(p,min_tmp);
        }

        long long left=-1;
        long long right=(long long)min_tmp*totalTrips;

        while(left+1<right){
            long long mid=(left+right)/2;
            long long tmp=0;
            for(auto p:time){
                tmp+=mid/p;
                if(tmp >= totalTrips) break;  // 提前退出优化
            }
            if(tmp<totalTrips)    left=mid;
            else                  right=mid;
        
        }
        return right;

    }
};
相关推荐
暗之星瞳2 小时前
线性回归+实例
算法·回归·线性回归
little~钰2 小时前
整体二分——上
算法
Swift社区2 小时前
LeetCode 447 - 回旋镖的数量
linux·算法·leetcode
java修仙传2 小时前
力扣hot100:路径总和III
数据结构·算法·leetcode
lang201509283 小时前
Sentinel黑白名单授权控制详解
java·算法·sentinel
leoufung3 小时前
题目介绍:LeetCode 79. Word Search
leetcode·word·深度优先
小O的算法实验室3 小时前
2023年IEEE TIV,GA-LNS算法+直升机救援调度,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
foundbug9993 小时前
Delta并联机器人正逆解实现
算法·机器人
职业码农NO.13 小时前
《算法与数据结构》:最短路径
数据结构·算法