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;

    }
};
相关推荐
一只齐刘海的猫15 分钟前
【Leetcode】找到字符串中所有字母异位词
算法·leetcode·职场和发展
海清河晏11137 分钟前
数据结构 | 八大排序
数据结构·算法·排序算法
IronMurphy2 小时前
【算法五十七】146. LRU 缓存
算法·缓存
凌波粒2 小时前
LeetCode--108.将有序数组转换为二叉搜索树(二叉树)
算法·leetcode·职场和发展
liulilittle2 小时前
KCC:在 BBR 思路上的一次探索
网络·tcp/ip·算法·bbr·通信·拥塞控制·kcc
浦信仿真大讲堂3 小时前
达索系统SIMULIA Abaqus 2026接触和约束的增强新功能介绍
人工智能·python·算法·仿真软件·达索软件
点云侠3 小时前
PCL 生成三棱锥点云
c++·算法·最小二乘法
兰令水3 小时前
leecodecode【面试150】【2026.6.13打卡-java版本】
java·算法·leetcode
临沂堇3 小时前
刷题日志 | Leetcode Hot 100 哈希
算法·leetcode·哈希算法
玉小格3 小时前
一次关于Python的总结
算法