1011 Capacity To Ship Packages Within D Days
Approach 1 Binary Search
Binary search 经典题目, 对理解左右边界更新条件很有帮助.
left,right的选择至少需要max(weights), 不然过不了一天;最多需要sum(weights), 一天就搬完全部了.helper function(weights,guess): 用来计算在这个搬运速度guess下,需要多少天搬完, 比较tricky, 需要分类讨论- 如果搬完今天还有剩余, 那么我们尝试明天继续搬,
i++ - 如果搬完今天正好, 那么我们尝试明天继续搬, 所需消耗总天数+1, 然后我们能量值reset. i.e.
i++,days_needed += 1,remaining = daily_capacity - 如果搬完发现能量不足以搬完,那么我们上一步就已经耗完所有能量了, 所需消耗总天数+1, 然后我们能量值reset以崭新的精神面貌重新面对新一天的工作. i.e.
i++,days_needed += 1,remaining = daily_capacity
- 如果搬完今天还有剩余, 那么我们尝试明天继续搬,
这个helper function有一个edge case,就是在第一种情况时,我们已经到了最后一个货物 因为不管你再有多少能量,已经没货物给你搬运了, 所以days_needed += 1, 收工!
关于左右边界的更新, if days_needed(weights,mid) <= days: 说明我们搬运速度过快了,我们需要更慢一点,但我们的solution space肯定在这半块,因为也存在days_needed(weights,mid) == days, 所以我们采取比较保守的更新策略,以防truncate掉最优的solution right = mid.
if days_needed(weights,mid) > days: 说明我们搬运速度过慢了,我们需要更快一点. 因为days_needed(weights,mid) > days, 我们的solution space必然不在这半块,所以我们可以更aggressive的更新. left = mid + 1
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
# find least weight capacity of the ship
left,right = max(weights), sum(weights)
def days_needed(weights,daily_capacity):
days_needed = 0
remaining = daily_capacity
i = 0
while i < len(weights):
remaining -= weights[i]
if remaining > 0:
i += 1
# for edge case, 虽然还有capacity,但是到头了+1天
if i == len(weights):
return days_needed + 1
elif remaining == 0:
# we just found enough, reset our capacity and move on
days_needed += 1
remaining = daily_capacity
i += 1
else:
# we can't do today, 重头再来一次
days_needed += 1
remaining = daily_capacity
return days_needed
while left < right:
mid = (left + right)//2
if days_needed(weights,mid) <= days:
# 太快了, 答案在这个solution space里,propogate strategy mild一点
right = mid
else:
# 太慢了
left = mid + 1
return left