题目描述
给你一个数组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 <= 1051 <= time[i], totalTrips <= 107
解决方案:
算法目标
给定多辆车的单趟完成时间和需要完成的总趟数,找出完成所有趟数所需的最少时间。
核心思路
确定时间范围:时间在
[0, 最慢车×总趟数]之间二分查找时间:尝试不同的时间,计算在该时间内能完成多少趟
寻找最小值:找到能满足总趟数要求的最小时间
算法步骤
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是最小的可行时间
优化亮点
提前退出:当趟数已达标时立即停止计算
开区间二分:避免边界处理复杂
类型安全:使用
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; } };