SWE · Coding

优先级Job与调用次数冷却:ready堆和eligible堆

冷却不是墙钟时间,同一次getJob还需定义是否推进计数。

题目重点:冷却不是墙钟时间,同一次getJob还需定义是否推进计数。

题意与假设

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

  • 训练:Job持久反复可执行,最高priority先,同priority最早注册先;ID非None、唯一。
  • 执行调用c后delay=M表示必须完整经过M次其他getJob调用,最早c+M+1再次可选;空结果调用也计一次。具体等号与是否重排需正式确认。

解题路线

  1. ready堆按(−priority,seq,id),waiting按(eligibleCall,seq,id)。每get先calls++并把所有到期Job移ready,再弹最高并挂到waiting。
  2. 就绪与优先级是两层约束,不能高优先但未到期也处理;不会扫描全部waiting找可用项。
  3. 没有删除或修改priority API,所以无需版本lazyheap;一旦增加这些操作,应为旧堆条目加版本或索引,防重复执行。严格优先可能饿死低优先,公平策略是另一合同。

手动走一遍

A高优先delay3,call1执行A,call2/3/4不能A,call5允许。无其他Job时三个中间调用返回None但推进计数。delay0每次调用都可执行,最高A可以一直赢过B;不要假称公平。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from heapq import heappush,heappop


class Scheduler:
    def __init__(self):
        self.jobs={};self.ready=[];self.waiting=[];self.calls=0;self.sequence=0

    def addJob(self,ident,priority,delay=0):
        if ident is None or ident in self.jobs or type(priority) is not int or type(delay) is not int or delay<0:raise ValueError("unique job and nonnegative delay required")
        self.jobs[ident]=(priority,delay,self.sequence)
        heappush(self.ready,(-priority,self.sequence,ident));self.sequence+=1

    def getJob(self):
        self.calls+=1
        while self.waiting and self.waiting[0][0]<=self.calls:
            _,seq,ident=heappop(self.waiting);priority,delay,_=self.jobs[ident]
            heappush(self.ready,(-priority,seq,ident))
        if not self.ready:return None
        neg,seq,ident=heappop(self.ready);priority,delay,_=self.jobs[ident]
        heappush(self.waiting,(self.calls+delay+1,seq,ident))
        return ident

复杂度

add O(logn),get需搬迁r到期项O((r+1)logn),每次执行对应一次挂起/到期,累计摊还按操作计。两堆总O(n)存储。

易错点与追问

容易失分的边界

  • 把delay3理解成“第三次含当前即可再次执行”会off-by-one。
  • 没有可用Job时阻塞与返回None是不同API,本文选择后者。

继续深挖

  • 若empty调用不推进计数,单一冷却Job如何解锁?
  • 加入取消/改优先级后怎样确保同Job不同时在两堆重复有效?
✓已复制微信号!