LeetCode 1011中等二分答案 · 贪心判定
在 D 天内送达包裹的能力 图解题解
这道题到底在问什么
传送带上的包裹必须按顺序装船,给定天数 days,求每天船的最小运载能力。
- weights
- [1,2,3,4,5,6,7,8,9,10]
- days
- 5
- 输出
- 15
最优解:一步一步想明白
- 3写一个 check(cap):按顺序贪心装船,装不下就开新一天;天数不超过 days 就可行。
- 4左=max(weights)=10,右=sum=55先锁定答案区间。真实代码里 l=max(weights),r=sum(weights)。
- 5check(13) 超过 5 天容量 13 放不下所有包裹在 5 天内送完,所以 13 以及更小容量全部丢掉。
- 6l 移到 14不可行就加大容量,左边整段灰掉。
- 7check(15) 正好 5 天容量 15 可行,但我们要最小容量,所以保留它并继续向左找。
- 8r = mid可行不代表答案就是它,可能还有更小的可行容量。
- 9check(14) 超过 5 天14 不可行,说明最小可行容量不在 14 这一侧。
- 10l = 15区间收敛到唯一答案。
- 11最小容量 15二分答案的终点就是“第一个满足 check 的值”。
- 12不能打乱包裹顺序题目要求按给定顺序运输,所以 check 必须线性扫描。
- 15“最小可行值 / 最大可行值”这类题,先找单调性,再写 check。
⚠️ 容易写错的地方
✗ 错:左边界写成 1
✓ 对:左边界必须是 max(weights)
容量小于最重包裹时当天根本装不下
✗ 错:check 里重排包裹
✓ 对:必须按原顺序贪心装船
题目要求传送带顺序不能改变
完整代码(Python)
Python
class Solution:
def shipWithinDays(self, weights, days):
def need_days(cap):
used = 1
cur = 0
for w in weights:
if cur + w > cap:
used += 1
cur = 0
cur += w
return used
l, r = max(weights), sum(weights)
while l < r:
mid = (l + r) // 2
if need_days(mid) <= days:
r = mid
else:
l = mid + 1
return l套路模板 · 最小可行值二分
class Solution:
def answer(self, nums):
def check(x):
return True
l, r = min_possible, max_possible
while l < r:
mid = (l + r) // 2
if check(mid):
r = mid
else:
l = mid + 1
return l复杂度
时间复杂度
O(n log S)
S=sum(weights),每次 check 扫一遍
空间复杂度
O(1)
只用几个变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 在 D 天内送达包裹的能力 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「贪心判定」,换最直接的暴力解会差在哪?+
贪心判定抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。