技术岗位 · Coding

每日重复跨日任务:整周期负载加余段扫描

长任务跨多天,区分一次性时间线和每天新启动的周期实例。

题目重点:长任务跨多天,区分一次性时间线和每天新启动的周期实例。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练合同:周期P内每个任务每天启动一次,持续d分钟,可跨任意多个周期;不同天实例不可合并,一个server同一时刻只能跑一实例。
  • 起点/时长同为整数分钟,半开执行区间;d=0不占用。源时刻23与23:00混写、是否每日重复仍需面试确认。

解题路线

  1. d=qP+r,稳态任意时刻有q个完整周期实例持续占用,加入baseline;余r分钟在周期圆环产生一个短弧。
  2. 若短弧不跨0,记[start,end)加1;跨0就拆成[start,P)及[0,end−P)。按时刻聚合事件后扫描,最大baseline+active是瞬时最少server下界。
  3. 允许每个实例自由分配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并发基线不再正确。

继续深挖

  • 如果只有一个日期范围内的新启动实例,怎样处理启动和结束边界?
  • 需要具体服务器排班时,如何构造有限窗口并证明周期重复策略?
✓已复制微信号!