哈希表在面试中的地位
哈希表把「查找是否存在 / 计数 / 存下标」从 O(n) 降到均摊 O(1),是 Week 1 算法闭环的最后一块拼图。与数组、双指针、滑动窗口组合,覆盖大量 Easy~Medium 题。
核心问题:键是什么?值存什么? 键可以是数值、字符、前缀和、状态压缩 bitmask;值可以是次数、下标、列表。
模式一:补数 / 配对
两数之和:遍历时查 target - nums[i] 是否已见。
def two_sum(nums, target):
seen = {}
for i, x in enumerate(nums):
need = target - x
if need in seen:
return [seen[need], i]
seen[x] = i
return []
字母异位词分组:键为排序后的字符串或 26 位计数签名。
模式二:频率计数
统计字符/元素出现次数,用于 anagram、多数元素(Boyer-Moore 也可)、Top K(配合堆)。
from collections import Counter
def is_anagram(s, t):
return Counter(s) == Counter(t)
滑动窗口题中,用两个 Counter 比较窗口是否与模式匹配(可优化为「有效字符种类差」)。
模式三:前缀和 + 哈希
连续子数组和为 k:
def subarray_sum(nums, k):
count = {0: 1}
prefix = ans = 0
for x in nums:
prefix += x
ans += count.get(prefix - k, 0)
count[prefix] = count.get(prefix, 0) + 1
return ans
count[0]=1 表示空前缀。若问「个数为偶数的最长子数组」类题,可对前缀和奇偶性哈希。
和可被 K 整除的子数组:前缀和 mod K,相同余数的下标间距即为合法长度。
模式四:去重与最长序列
最长连续序列(O(n)):先 set(nums),只对「序列起点」(x-1 不在 set)向右延伸。
最长无重复子串也可用哈希存最后下标(见 week01-sliding-window)。
设计自定义哈希键
- 元组
(i, j)表示坐标,用于 BFS visited。 - frozenset 或排序 tuple 作为图的无向边键。
- 状态
(pos, mask)用于 DP + 记忆化。
map 无序、非线程安全,并发需 sync.Map 或加锁;Week 2 会深入 week02-go-slice-map。
复杂度与边界
- 时间:单次遍历 O(n),嵌套哈希操作注意均摊。
- 空间:O(n) 存储键;面试主动说明 trade-off。
- 整数溢出:前缀和用 Python 无虞;Java/Go 需注意。
练习路线
Week 1 四篇(数组、双指针、窗口、哈希)构成「线性扫描」完整工具箱,进入 Week 2 链表与树之前务必熟练。
实战巩固与面试表达
本篇属于 8 周冲刺 week01-hash-table 主题。复习时先闭卷回答 frontmatter 中三张 flashcard,再展开口述两个「为什么」:为什么这种方案能 work、边界失败时如何降级。与相邻章节对照:算法篇强调复杂度与模板,Go 篇强调工程默认写法,中间件篇强调线上故障案例。
动手与自检清单
用 25 分钟限时做 1 道相关练习题或画出一张架构/数据结构示意图;用 5 分钟写 STAR 片段说明你在项目里是否用过类似技术。记录 3 个面试追问及你的标准答法,存入 /zh/notebook/master-plan 笔记。若某点不熟,回到对应 /chapters 交互 Lab 重新走一遍流程,比死记卡片更有效。
易错点提醒
避免只背名词不会画图;避免只说优点不谈 trade-off(性能、一致性、运维成本至少提一项);避免把学习 Demo 说成百万 QPS 生产。回答时使用「场景 → 方案 → 结果 → 反思」四段式,体现工程成熟度。