Python技术迷

公司宣布破产,每人拿了70000元补偿金。就在大家收拾准备走人时,结果老板说:有个新公司谁愿意去?工资翻倍,但必须自愿放弃赔偿金。

我在网上看到一个帖子,真是把打工人的心态拿去过山车了。公司先宣布破产,每人补7万,大家盒子都快收好了,结果老板又来一句:我这边有个新公司,谁愿意去,工资翻倍,但赔偿金得自愿放弃。

Image

这话一出,味儿就不对了。

有网友说得很直接:先赔钱,再谈入职,别把自愿两个字说得像免死金牌。还有人吐槽:新公司要是真这么好,干嘛非得拿赔偿金当门票?

算法题:日志速率限制器

这题表面看不复杂,就是“同一条日志 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

这个版本更接近“滑动窗口”的味道。不是题目必需,但写出来会显得你考虑过工程场景。

这题不难,关键是别把它写成纯规则判断题。面试官一般想看的,其实就两件事:你能不能快速把“消息 -> 最近一次打印时间”这个映射抽出来;你会不会在边界条件上写错半拍。把这两个点写稳,基本就够了。