题目重点:冷却不是墙钟时间,同一次getJob还需定义是否推进计数。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练:Job持久反复可执行,最高priority先,同priority最早注册先;ID非None、唯一。
- 执行调用c后delay=M表示必须完整经过M次其他getJob调用,最早c+M+1再次可选;空结果调用也计一次。具体等号与是否重排需正式确认。
解题路线
- ready堆按(−priority,seq,id),waiting按(eligibleCall,seq,id)。每get先calls++并把所有到期Job移ready,再弹最高并挂到waiting。
- 就绪与优先级是两层约束,不能高优先但未到期也处理;不会扫描全部waiting找可用项。
- 没有删除或修改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不同时在两堆重复有效?
