震惊!这些题也能用二分查找做
Posted 胖钰钰的生活琐记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了震惊!这些题也能用二分查找做相关的知识,希望对你有一定的参考价值。
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
1482. Minimum Number of Days to Make m Bouquets
Given an integer array bloomDay
, an integer m
and an integer k
.
We need to make m
bouquets. To make a bouquet, you need to use k
adjacent flowers from the garden.
The garden consists of n
flowers, the ith
flower will bloom in the bloomDay[i]
and then can be used in exactly one bouquet.
Return the minimum number of days you need to wait to be able to make m
bouquets from the garden. If it is impossible to make m
bouquets return -1.
Example 1:
Input: bloomDay = [1,10,3,10,2], m = 3, k = 1
Output: 3
Explanation: Let's see what happened in the first three days. x means flower bloomed and _ means flower didn't bloom in the garden.
We need 3 bouquets each should contain 1 flower.
After day 1: [x, _, _, _, _] // we can only make one bouquet.
After day 2: [x, _, _, _, x] // we can only make two bouquets.
After day 3: [x, _, x, _, x] // we can make 3 bouquets. The answer is 3.
Example 2:
Input: bloomDay = [1,10,3,10,2], m = 3, k = 2
Output: -1
Explanation: We need 3 bouquets each has 2 flowers, that means we need 6 flowers. We only have 5 flowers so it is impossible to get the needed bouquets and we return -1.
Example 3:
Input: bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
Output: 12
Explanation: We need 2 bouquets each should have 3 flowers.
Here's the garden after the 7 and 12 days:
After day 7: [x, x, x, x, _, x, x]
We can make one bouquet of the first three flowers that bloomed. We cannot make another bouquet from the last three flowers that bloomed because they are not adjacent.
After day 12: [x, x, x, x, x, x, x]
It is obvious that we can make two bouquets in different ways.
Example 4:
Input: bloomDay = [1000000000,1000000000], m = 1, k = 1
Output: 1000000000
Explanation: You need to wait 1000000000 days to have a flower ready for a bouquet.
Example 5:
Input: bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
Output: 9
Constraints:
bloomDay.length == n
1 <= n <= 10^5
1 <= bloomDay[i] <= 10^9
1 <= m <= 10^6
1 <= k <= n
这道题直接考虑dfs的话,即便用memorization会超时
所以我们从天数考虑,我们可以得到在d天可以形成的花束数量吗?是的,我们可以运行一次简单的计数,方法是检查开花的当天是否小于或等于d,以获取相邻的大于或等于k的花朵的数量。
class Solution:
def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
if m*k > len(bloomDay):
return -1
def getBouq(day):
result = 0
count = 0
for i in range(len(bloomDay)):
if bloomDay[i] <= day:
count += 1
else:
count = 0
if count == k:
result += 1
count = 0
return result
left = min(bloomDay)
right = max(bloomDay)
while left <= right:
mid = left + (right-left)//2
if getBouq(mid) < m:
left = mid + 1
else:
right = mid - 1
return left
774. Minimize Max Distance to Gas Station
On a horizontal number line, we have gas stations at positions stations[0], stations[1], ..., stations[N-1], where N = stations.length.
Now, we add K more gas stations so that D, the maximum distance between adjacent gas stations, is minimized.
Return the smallest possible value of D.
Example:
Input: stations = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], K = 9
Output: 0.500000
Note:
stations.length will be an integer in range [10, 2000].
stations[i] will be an integer in range [0, 10^8].
K will be an integer in range [1, 10^6].
Answers within 10^-6 of the true value will be accepted as correct.
首先要明白这题不是贪心,比如
[10, 19, 25, 27, 56, 63, 70, 87, 96, 97],K = 3
其两两之间的距离为:
9,6,2,29,7,7,17,9,1
如果按照贪心,会先将29分开,变成两个14.5,然后会将17分开,变成两个8.5,还剩一个加油站,会将其中一个14.5分开,变成两个7.25。但是这样弄下来,最大的距离还是14.5,而实际上我们有更好的办法,我们用两个加油站将29三等分,会变成三个9.67,然后用剩下的一个去分17,得到两个8.5,此时最大距离就变成了9.67,这才是最优的解法。
这题如果用dp,时间复杂度是O(NK^2), N 是 stations的长度
但是如果用二分查找,时间复杂度就是O(NlogW),其中 N 是 stations 的长度,W = 10^14(W是所有可能答案的范围10^8/10^-6)
问题转化为:
有 k 个加油站,有没有可能让最小的最大距离小于等于 D
假设答案为 D*, 对于 d < D*,possibe(d) = False,对于d > D*,possible(d) = True。针对单调问题的二分搜索是一个很典型的做法,重点是 possible(D) 的实现。
class Solution:
def minmaxGasDist(self, stations: List[int], K: int) -> float:
def count(d):
res = 0
for i in range(1, len(stations)):
res += int((stations[i] - stations[i-1]) / d)
return res
left = 0
right = 10**8
while right-left > 0.000001:
mid = left + (right-left)/2
if count(mid) > K:
left = mid
else:
right = mid
return right
彩蛋:盆盆是
以上是关于震惊!这些题也能用二分查找做的主要内容,如果未能解决你的问题,请参考以下文章