题目重点:长任务跨多天,区分一次性时间线和每天新启动的周期实例。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练合同:周期P内每个任务每天启动一次,持续d分钟,可跨任意多个周期;不同天实例不可合并,一个server同一时刻只能跑一实例。
- 起点/时长同为整数分钟,半开执行区间;d=0不占用。源时刻23与23:00混写、是否每日重复仍需面试确认。
解题路线
- d=qP+r,稳态任意时刻有q个完整周期实例持续占用,加入baseline;余r分钟在周期圆环产生一个短弧。
- 若短弧不跨0,记[start,end)加1;跨0就拆成[start,P)及[0,end−P)。按时刻聚合事件后扫描,最大baseline+active是瞬时最少server下界。
- 允许每个实例自由分配server且不迁移时,将无限时间线区间按起点分配,所需台数等于最大重叠;但如果强制每种任务固定绑定同一server,多日自重叠甚至不可能,不能用此答案。
手动走一遍
P=10,任务(8,5)每天占8..10及0..3;任务(1,2)占1..3,两者峰值2。P=10,单任务d=25:baseline2+余5的峰值1,所以需要3台;若只有一次执行则只需1台。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def daily_servers(jobs, period):
if type(period) is not int or period <= 0:
raise ValueError("positive integer period required")
baseline, events = 0, {}
def interval(a,b):
if a < b:
events[a] = events.get(a,0)+1
events[b] = events.get(b,0)-1
for start, duration in jobs:
if type(start) is not int or type(duration) is not int or duration < 0:
raise ValueError("integer start and nonnegative duration required")
whole, remainder = divmod(duration, period)
baseline += whole
start %= period
end = start + remainder
if end <= period:
interval(start,end)
else:
interval(start,period)
interval(0,end-period)
active = best = baseline
for t in sorted(events):
active += events[t]
best = max(best,active)
return best
复杂度
n任务事件≤4n,O(nlogn)时间、O(n)空间,duration很大也不逐天展开。
易错点与追问
容易失分的边界
- 同时结束开始在半开区间可复用;聚合delta避免虚假峰值。
- 若不同天同任务允许重叠合成一条常驻服务,q并发基线不再正确。
继续深挖
- 如果只有一个日期范围内的新启动实例,怎样处理启动和结束边界?
- 需要具体服务器排班时,如何构造有限窗口并证明周期重复策略?
