二分算法02
- [1. 每个小孩最多能分到多少糖果](#1. 每个小孩最多能分到多少糖果)
- [2. 准时到达的列车最小时速](#2. 准时到达的列车最小时速)
- [3. 在 D 天内送达包裹的能力](#3. 在 D 天内送达包裹的能力)
1. 每个小孩最多能分到多少糖果
给你一个 下标从 0 开始 的整数数组 candies 。数组中的每个元素表示大小为 candies[i] 的一堆糖果。你可以将每堆糖果分成任意数量的 子堆 ,但 无法 再将两堆合并到一起。
另给你一个整数 k 。你需要将这些糖果分配给 k 个小孩,使每个小孩分到 相同 数量的糖果。每个小孩可以拿走 至多一堆 糖果,有些糖果可能会不被分配。
返回每个小孩可以拿走的 最大糖果数目 。
真题点击此处:2226. 每个小孩最多能分到多少糖果
解题思路:
假设有一个长度为 n 的数组 candies,表示每个糖果的数量。现在我们希望将这些糖果平均分配给 k 个孩子。我们需要找到一个最大的正整数 x,使得将每个糖果分成 x 份后,每个孩子都可以得到至少一份,并且可以得到最大总糖果数。
- 我们首先定义两个指针 left 和 right,分别指向可能的最小值 1 和最大值 max(candies)。
- 然后我们使用二分查找的方法,不断缩小 left 和 right 的范围,直到 left > right 为止。
- 在每次循环中,我们计算 mid = (left + right) // 2,表示当前的糖果份数。
- 接着,我们遍历数组 candies,计算出将每个糖果分成 mid 份后,可以得到的总糖果数 ans。
- 如果 ans < k,说明当前的份数过多,我们需要将 right 指针左移,将搜索范围从右半部分继续缩小。
- 如果 ans >= k,说明当前份数过少或刚好符合要求,我们需要将 left 指针右移,将搜索范围从左半部分继续缩小。
- 最终返回 left - 1,即为最大的正整数 x。
具体解题思路可以总结为以下几点:
- 定义两个指针 left 和 right,分别指向可能的最小值 1 和最大值 max(candies)。
- 使用二分查找的方法,不断缩小 left 和 right 的范围,直到 left > right 为止。
- 在每次循环中,计算 mid = (left + right) // 2,表示当前的糖果份数。
- 遍历数组 candies,计算出将每个糖果分成 mid 份后,可以得到的总糖果数 ans。
- 如果 ans < k,将 right 指针左移,将搜索范围从右半部分继续缩小。
- 如果 ans >= k,将 left 指针右移,将搜索范围从左半部分继续缩小。
- 最终返回 left - 1,即为最大的正整数 x。
这种方法利用了二分查找的特性,不断缩小搜索范围,最终得到符合要求的最大的正整数 x。
以下为代码实现:
python
class Solution:
def maximumCandies(self, candies: List[int], k: int) -> int:
left, right = 1, max(candies)
while left <= right:
mid = (left + right) // 2
ans = 0
for c in candies:
ans += c // mid
if ans < k:
right = mid - 1
else:
left = mid + 1
return left - 1
时间复杂度:O(nlogm),其中 n 为糖果数组 candies 的长度,m 为糖果数组中最大的数值。
空间复杂度:O(1),该算法只使用了常数级别的额外空间用于存储变量。
2. 准时到达的列车最小时速
给你一个浮点数 hour ,表示你到达办公室可用的总通勤时间。要到达办公室,你必须按给定次序乘坐 n 趟列车。另给你一个长度为 n 的整数数组 dist ,其中 dist[i] 表示第 i 趟列车的行驶距离(单位是千米)。
每趟列车均只能在整点发车,所以你可能需要在两趟列车之间等待一段时间。
例如,第 1 趟列车需要 1.5 小时,那你必须再等待 0.5 小时,搭乘在第 2 小时发车的第 2 趟列车。
返回能满足你准时到达办公室所要求全部列车的 最小正整数 时速(单位:千米每小时),如果无法准时到达,则返回 -1 。
生成的测试用例保证答案不超过 107 ,且 hour 的 小数点后最多存在两位数字 。
真题点击此处:1870. 准时到达的列车最小时速
解题思路:
假设有一个长度为 n 的数组 dist,表示一系列区间的距离,以及一个代表旅行所需总时间的浮点数 hour。现在我们需要找到一个最小的速度 x,使得以这个速度行驶的话,可以在规定时间内完成旅程。
- 首先定义两个指针 left 和 right,分别指向可能的最小速度 1 和最大速度 10^7。
- 使用二分查找的方法,不断缩小 left 和 right 的范围,直到 left > right 为止。
- 在每次循环中,计算 mid = (left + right) // 2,表示当前的速度。
- 遍历数组 dist,计算以速度 mid 行驶时,所需的总时间 time。
- 如果 time <= hour,说明当前速度可以满足要求,我们需要将 right 指针左移,将搜索范围从右半部分继续缩小。
- 如果 time > hour,说明当前速度过慢,我们需要将 left 指针右移,将搜索范围从左半部分继续缩小。
- 最终返回 left,即为最小的速度 x。
具体解题思路可以总结为以下几点:
- 定义两个指针 left 和 right,分别指向可能的最小速度 1 和最大速度 10^7。
- 使用二分查找的方法,不断缩小 left 和 right 的范围,直到 left > right 为止。
- 在每次循环中,计算 mid = (left + right) // 2,表示当前的速度。
- 遍历数组 dist,计算以速度 mid 行驶时,所需的总时间 time。
- 如果 time <= hour,将 right 指针左移,将搜索范围从右半部分继续缩小。
- 如果 time > hour,将 left 指针右移,将搜索范围从左半部分继续缩小。
- 最终返回 left,即为最小的速度 x。
这种方法利用了二分查找的特性,不断缩小搜索范围,最终得到符合要求的最小速度 x。
以下为代码实现:
python
class Solution:
def minSpeedOnTime(self, dist: List[int], hour: float) -> int:
left, right = 1, 10 ** 7
while left <= right:
mid = (left + right) // 2
time = 0
for i in range(len(dist) - 1):
time += (dist[i] + mid - 1) // mid
time += dist[-1] / mid
if time <= hour:
right = mid - 1
else:
left = mid + 1
return left if len(dist) < hour + 1 else -1
时间复杂度: O(nlogm),其中 n 为距离数组 dist 的长度,m 为距离数组中的最大值。
空间复杂度:O(1),该算法只使用了常数级别的额外空间用于存储变量。
3. 在 D 天内送达包裹的能力
传送带上的包裹必须在 days 天内从一个港口运送到另一个港口。
传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量(weights)的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。
返回能在 days 天内将传送带上的所有包裹送达的船的最低运载能力。
真题点击此处:1011. 在 D 天内送达包裹的能力
解题思路:
- 定义两个指针 left 和 right,分别指向货物重量的最大值和总和。
- 使用二分查找的方法,不断缩小 left 和 right 的范围,直到 left > right 为止。
- 在每次循环中,计算 mid = (left + right) // 2,表示当前的运载能力。
- 遍历货物重量数组 weights,模拟运输过程,统计完成的运输批次 ans。
- 根据 ans 与规定天数 days 的关系,调整 left 和 right 指针的位置。
- 最终返回 left,即为最低的运载能力 x。
以下为代码实现:
python
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
left, right = max(weights), sum(weights)
while left <= right:
mid = (left + right) // 2
ans = 0
s = mid
i = 0
while i < len(weights):
if s >= weights[i]:
s -= weights[i]
i += 1
else:
ans += 1
s = mid
ans += 1
if ans <= days:
right = mid - 1
else:
left = mid + 1
return left
时间复杂度:O(nlogm),其中 n 为重量数组 weights 的长度,m 为所有重量的总和。
空间复杂度:O(1),该算法只使用了常数级别的额外空间用于存储变量。