你的 Python 老毛病
写完代码逐条对一遍。这些都是准备面试时反复出过错的地方,各题的「易错点」里提到时会链回这里。
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
- 需要反复处理的地方用
while,不是if:单调栈弹栈(739. Daily Temperatures、42. Trapping Rain Water 的栈写法)、双堆平衡、BFS 外层循环while q。
边界和差一(off-by-one)
- 网格边界写成
0 <= nr < n;行列不等时分开写0 <= nr < m and 0 <= nc < n。 - 宽度、下标的差一最容易错:42. Trapping Rain Water、498. Diagonal Traverse、969. Pancake Sorting、68. Text Justification。写完用小例子手动追一遍。
- 倒序
range的终点:range(target, x - 1, -1)才包含 x(416. Partition Equal Subset Sum)。 - 层数从 -1 开始还是 0 开始,决定最后要不要减一(1162. As Far from Land as Possible)。
常用模块
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))。
数值和递归
- 平均数要返回浮点数时写
/ 2,不要写成// 2(295. Find Median from Data Stream)。 - 默认递归深度上限是 1000,很深的图或树(比如 10⁵ 个点的长链)会 RecursionError,要能改成显式栈(加边判环:新边是否合法、428. Serialize and Deserialize N-ary Tree)。
- 浮点数比较留 eps,不要用哈希精确匹配(x 轴上是否有两点距离为 d、负权环检测(Bellman-Ford) 的汇率套利)。
写法习惯
- 复杂结构先写不变式注释,再写代码(例:双堆的大小关系、单调栈里存的是什么)。
- 在不能运行的文档里写代码时没有自动缩进,统一用 4 个空格。
threading.Event 和多线程
(Verkada 迁移时补充)
-
ev.wait(timeout=5)返回True是等到了、False是超时,两个分支都要写。有人在 Verkada Onsite 被反复打断,漏写了超时的else就挂了(threading.Event:多线程同步)。把它写成肌肉记忆:pythonif 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。
问过 Claude 的(0)
rev 3 · 更新于 10-11 00:55