公司宣布破产,每人拿了70000元补偿金。就在大家收拾准备走人时,结果老板说:有个新公司谁愿意去?工资翻倍,但必须自愿放弃赔偿金。
我在网上看到一个帖子,真是把打工人的心态拿去过山车了。公司先宣布破产,每人补7万,大家盒子都快收好了,结果老板又来一句:我这边有个新公司,谁愿意去,工资翻倍,但赔偿金得自愿放弃。
这话一出,味儿就不对了。
有网友说得很直接:先赔钱,再谈入职,别把自愿两个字说得像免死金牌。还有人吐槽:新公司要是真这么好,干嘛非得拿赔偿金当门票?
算法题:日志速率限制器
这题表面看不复杂,就是“同一条日志 10 秒内别重复打印”。真写的时候,坑基本都在边界上:到底是拦,还是放;是按消息维度限流,还是全局限流;数据结构怎么选,才能既快又不把内存拖爆。
先看题意,通常会给你两个输入:timestamp 和 message。如果这条 message 上一次打印时间距离当前不到 10 秒,就返回 False;否则返回 True,并把这次时间记下来。
这类题第一反应其实就是哈希表,没必要绕。
classLogger:
def__init__(self):
self.last_print = {}
defshould_print_message(self, timestamp: int, message: str) -> bool:
prev = self.last_print.get(message)
if prev isnotNoneand timestamp - prev < 10:
returnFalse
self.last_print[message] = timestamp
returnTrue
这个写法已经能过大部分测试。查一次字典,更新一次字典,时间复杂度基本就是 O(1)。
拿一组数据走一下会更直观:
logger = Logger()
print(logger.should_print_message(1, "error")) # True
print(logger.should_print_message(2, "error")) # False
print(logger.should_print_message(11, "error")) # True
print(logger.should_print_message(12, "db")) # True
print(logger.should_print_message(15, "db")) # False
这里真正要盯住的不是“10 秒”这几个字,而是判断条件到底写成什么。很多人会顺手写成:
if prev and timestamp - prev <= 10:
returnFalse
这段有两个问题。
第一个,prev 如果刚好是 0,判断会出错,虽然有些题目时间戳从 1 开始,不一定踩中,但写法本身不稳。
第二个,<= 10 和 < 10 不是一回事。题目一般说的是“10 秒内不重复打印”,那第 11 秒是可以放行的。也就是:
timestamp - prev < 10
不是:
timestamp - prev <= 10
再往下想一步,这个解法还有个实际问题:字典会一直涨。假设日志种类特别多,历史 key 永远不清,内存就会越来越大。面试题通常默认不追这个,但如果你想把它写得更像线上一点,可以顺手带个清理思路。
比如维护一个队列,把超过窗口的数据淘掉:
from collections import deque
classLoggerWithClean:
def__init__(self):
self.last_print = {}
self.q = deque()
defshould_print_message(self, timestamp: int, message: str) -> bool:
while self.q and timestamp - self.q[0][0] >= 10:
old_ts, old_msg = self.q.popleft()
if self.last_print.get(old_msg) == old_ts:
self.last_print.pop(old_msg)
prev = self.last_print.get(message)
if prev isnotNoneand timestamp - prev < 10:
returnFalse
self.last_print[message] = timestamp
self.q.append((timestamp, message))
returnTrue
这个版本更接近“滑动窗口”的味道。不是题目必需,但写出来会显得你考虑过工程场景。
这题不难,关键是别把它写成纯规则判断题。面试官一般想看的,其实就两件事:你能不能快速把“消息 -> 最近一次打印时间”这个映射抽出来;你会不会在边界条件上写错半拍。把这两个点写稳,基本就够了。