面试准备

你的 Python 老毛病

本页目录
  1. heapq
  2. while 和 if
  3. 边界和差一(off-by-one)
  4. 常用模块
  5. 数值和递归
  6. 写法习惯
  7. threading.Event 和多线程
  8. 字典缺键、文件结构、无穷大

写完代码逐条对一遍。这些都是准备面试时反复出过错的地方,各题的「易错点」里提到时会链回这里。

heapq

  • heapq 是一组模块函数,不是类:堆就是一个普通 list,用 heapq.heappush(h, x)、heapq.heappop(h),堆顶是 h[0]。不要写成 h.push(x)。
  • Python 只有小顶堆。大顶堆靠存负数:放进去取负,拿出来再取负,堆顶是 -h[0](例:295. Find Median from Data Stream 的双堆)。
  • 「弹一个再压一个」用 heapq.heapreplace(h, x),一次 O(log n)(例:253. Meeting Rooms II)。

while 和 if

边界和差一(off-by-one)

常用模块

  • from collections import deque 拼对;队列用 deque.popleft(),不要用 list.pop(0)(后者每次 O(n))。
  • defaultdict(list) / defaultdict(set) 省掉判空;bisect.bisect_left / bisect.insort 处理有序列表。
  • random.choice 只能用在 list 上,不能直接用在 set 上(380. Insert Delete GetRandom O(1))。

数值和递归

写法习惯

  • 复杂结构先写不变式注释,再写代码(例:双堆的大小关系、单调栈里存的是什么)。
  • 在不能运行的文档里写代码时没有自动缩进,统一用 4 个空格。

threading.Event 和多线程

(Verkada 迁移时补充)

  • ev.wait(timeout=5) 返回 True 是等到了、False 是超时,两个分支都要写。有人在 Verkada Onsite 被反复打断,漏写了超时的 else 就挂了(threading.Event:多线程同步)。把它写成肌肉记忆:

    python
    if ev.wait(timeout=5):
        ev.clear()
        data = state.get(key)
    else:
        raise TimeoutError(...)
    
  • 生产方先写 state 再 set(),否则被唤醒的线程可能读到空;等到之后记得 clear()。

  • 线程间传数据优先用 queue.Queue(自带锁和 get(timeout=)),不要拿 list 加 sleep 轮询(Camera API:长轮询取日志)。

  • CPython 有 GIL,纯 Python 的 CPU 密集循环用线程不会更快;被问「多线程加速」时要能说出这一点(867. Transpose Matrix)。

字典缺键、文件结构、无穷大

chat 对话里问过、单独写成了概念题的几处,这里只列要点,展开看题目页。

  • setdefault 的默认值总会先求值:d.setdefault(k, []) 每次都新建一个列表再丢弃;默认值开销大时改成 if k not in d: d[k] = ...。详见 Python 字典缺键怎么处理。
  • defaultdict 读一下就插入键:if d["x"]: 会把 "x" 写进去;检查存在用 "x" in d 或 d.get("x")。返回给调用方前转成 dict(...)。C++ 的 m[k] 同样有这个坑。
  • 计数直接用 Counter,不要自己拼 defaultdict(int) 再排序。
  • 测试代码放进 main(),再用 if __name__ == "__main__": 包起来:不包函数时测试里的变量是全局变量,Solution 里拼错的名字会悄悄用到它,不报错。详见 用 Python 写算法题的结构。
  • Python 的 int 没有最大值:初始值用 float('inf') / math.inf;必须是 int 时用 sys.maxsize;题目给了 32 位范围就写 2**31 - 1。

rev 3 · 更新于 10-11 00:55