labuladong 如何运用二分查找算法
875. 爱吃香蕉的珂珂
canFinish()
函数:当前速度下,能吃完的小时数(注意要向上整除)- 最小速度为1,最大速度为数组中最大值。因此利用二分查找框架求h(h相当于二分查找中的目标值),注意当计算的时间与要求的时间相等时,也是更新右边界。最后返回左边界
- 关于向上整除(
pile
和speed
都是int型)- python
- python3:
pile/speed
是传统除法,除不完时有小数。因此向上整除可以写为math.ceil(pile / speed)
- python2.6及以前:
pile/speed
是向下整除,除不完时无小数(如:17/6=2)。因此向上整除不能写为math.ceil(pile / speed)
。要根据是否有余数,将h += math.ceil(pile / speed)
改为h += (pile/ speed)+ (1 if pile % speed>0 else 0)
- python2/python3统一:
int(a/b)
和a//b
都表示向下整除。所以可以根据是否有余数,将向上整除统一写为h += int(pile/ speed)+ (1 if pile % speed>0 else 0)
或h += pile// speed+ (1 if pile % speed>0 else 0)
- 只要
pile
和speed
中,任意一个为浮点型,/
就表示传统除法。因此可以通过speed+0.0
或者float(speed)
,将向上整除写为h += math.ceil(pile / (speed+0.0))
或者h += math.ceil(pile / float(speed))
- python3:
- C++:默认的
/
表示向下除法。可以通过speed+0.0
或者float(speed)
将int型的speed转成float,再用/
进行传统除法,最后用ceil()
将其向上转换 - 如果不想用ceil函数,则两个数相除向上取整可以写为
(a + b - 1) / b
- python
class Solution(object):
def minEatingSpeed(self, piles, H):
"""
:type piles: List[int]
:type H: int
:rtype: int
"""
import math
# 当前速度下需要的时间
def canFinish(piles, speed):
h = 0
for pile in piles:
h += math.ceil(pile / (speed+0.0)) # 或者 h += math.ceil(pile / float(speed))
return h
# 二分查找
l = 1
r = max(piles)
while l <= r:
speed = l + (r - l) // 2
if canFinish(piles, speed) > H: # 速度太慢
l = speed + 1
elif canFinish(piles,speed) <= H: # 速度太快
# 因为是找左边界,所以若相等,更新右边界
r = speed - 1
return l
###################################
class Solution(object):
def minEatingSpeed(self, piles, h):
"""
:type piles: List[int]
:type h: int
:rtype: int
"""
import math
def can_finish(piles,speed):
time=0
for i in piles:
time+=math.ceil((i+0.0)/speed)
return True if time<=h else False
l=1
r=max(piles)
while l<=r:
mid=l+(r-l)//2
if can_finish(piles,mid):
r = mid - 1
else:
l = mid + 1
return l
class Solution {
public:
int canFinish(vector<int> &piles, int speed) {
int time = 0;
for (int &i:piles) {
time += ceil(i / (speed+0.0));
// time += ceil(i / float(speed));
}
return time;
}
int minEatingSpeed(vector<int> &piles, int h) {
int l = 1;
int r = *max_element(piles.begin(), piles.end());
while (l <= r) {
int speed = l + (r - l) / 2;
if (canFinish(piles, speed) > h) {l = speed + 1;}
else {
r = speed - 1;
}
}
return l;
}
};
1011.在D天内送达包裹的能力
与上题思路相同,只是
- cap 的最小值和最大值分别为
max(weights)
和sum(weights)
。 - 按照有无超过容量来更新完成的天数
d
class Solution(object):
def shipWithinDays(self, weights, D):
"""
:type weights: List[int]
:type D: int
:rtype: int
"""
# 当前capacity下完成的天数
def canFinish(weights,cap):
cur_w=0
d=1
for i in weights:
if cur_w+i>cap: # 超过容量了,放不下,天数加1,当前容量更新为i
d+=1
cur_w=i
else:
cur_w+=i # 没有超过,当前容量+i
return d
# 二分搜索找左边界
l=max(weights)
r=sum(weights)
while l<=r:
cap=l+(r-l)//2
if canFinish(weights, cap)>D:
l=cap+1
elif canFinish(weights, cap)<=D:
r=cap-1
return l