1. 问题描述:
给你一个数组 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 <= 10 ^ 5
1 <= time[i], totalTrips <= 10 ^ 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-time-to-complete-trips/
2. 思路分析:
分析题目可以知道数据范围为10 ^ 5(对于中等难度的问题首先看数据范围,根据数据范围猜可以使用哪些算法),所以需要将时间复杂度控制到O(n)或者是O(nogn)以内所以大概可以使用二分,树状数组,线段树,堆,最短路径这些算法,由题目可知道我们需要求解出一个最小的时间x使得可以至少可以完成totalTrips 旅途,所以属于满足某个条件限制的最值问题,根据这个特点我们首先需要想到的是能否使用二分来解决,能够使用二分解决的一个充分必要条件是我们需要找到一个性质使得当前枚举的答案具有二段性,若当前的枚举的答案为mid,也即当前的时间为mid,那么此时每辆公交车完成的旅途的数目为mid / time[i],将当前时间为mid的所有公交车完成的旅途数量加起来判断是否大于等于totalTrips,如果满足说明当前的mid是满足条件的,所以大于等于mid的时间都是满足要求的,所以答案在mid或者mid的左边,否则答案在mid的右边,这样我们就找到了一个性质使得当前枚举的答案是具有二段性的,可以将答案确定在mid的左边还是右边,所以可以使用二分来解决。对于二分来说核心是找到这个性质,这个性质可以使用check函数来实现,然后我们需要确定枚举的答案范围,可以发现答案最小是1,由于time[i]最大是10 ^ 7,而totalTrips最大也是10 ^ 7,所以答案最大为10 ^ 14.
3. 代码如下:
from typing import List
class Solution:
# 判断当前时间为t的时候完成旅途的数量是否大于等于m
def check(self, mid: int, time: List[int], m: int):
count = 0
for x in time:
# 当前时刻为mid的时候可以完成多少次的旅程
count += mid // x
if count >= m: return True
return False
# 二分查找
def minimumTime(self, time: List[int], m: int) -> int:
# 因为每一次最多需要10 ^ 7时间才可以完成一趟旅程, 最多为10 ^ 7趟旅程所以答案最多为10 ^ 14
l, r = 1, 10 ** 14 + 10
while l < r:
mid = l + r >> 1
if self.check(mid, time, m):
r = mid
else:
l = mid + 1
return r