news 2025/12/17 21:31:56

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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防止溢出

函数源码:

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; } };
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!