Python算法训练序列

基础概念 · Unit 00

刷题前置:Hashing Fundamentals

哈希不是一个代码模板,
而是一种“把对象直接送到位置”的思想。

没有哈希时,判断一个元素是否出现过,往往需要逐个扫描历史。哈希通过一个确定的映射规则,把对象转换为桶位置,从而在平均情况下快速完成查询、插入和更新。

这个页面使用 h(x)=x mod 7 作为教学模型。真实 Python 的 set 和 dict 使用更复杂的哈希与冲突处理机制,但核心思想相同:由键快速定位存储位置。
CHAPTER 01 / THE COGNITIVE ATLAS

第 1 章 · 认知梯度全景图

数组与哈希:从数值表示出发,练习用集合、映射与频次记录状态。

12 个后续单元
贯穿本章的统一框架观察对象 → 表示状态 → 查询历史 → 更新记录。先决定要记住什么,再选择数位变量、集合或映射。

从基础到复合任务,每一步增加一种决策

这里的梯度描述认知任务的递进,不等同于题库的难度标签。点击题目可进入对应单元。

起点 · Unit 00 数值表示、哈希与状态记录。先理解状态、操作与不变量,再沿下列路线练习。
  1. 01

    数位与进位

    先用少量变量表示未处理数位和进位,理解逐步消费输入。

  2. 02

    存在与索引

    从“出现过没有”升级为“在哪里出现”,建立先查询、后写入的顺序。

  3. 03

    频次与一致性

    值的含义从索引变成数量或映射关系,学习检查多种状态。

  4. 04

    等价类与状态图

    主动设计规范化键,或用集合判断起点与循环。

  5. 05

    组合与多维约束

    将配对、区间与行列宫关系转成可以查询的历史状态。

每道题在框架中的具体形式

用同一组问题定位每个单元,再观察迁移题改变了哪个条件。进入写代码环节后,学习地图会收起,留出独立思考的空间。

UNIT 01数位与进位

#9 回文数

保存的状态
未消费的高位整数与已经反转的低位。
查询与更新
逐次取最低位,消费原数位,把低位积累为反向表示。
正确性契约
两部分分别表示同一整数尚未处理与已经处理的数位。
边界与增量
负数和非零尾零先排除;奇数位中心不能重复比较。
迁移 · #7 整数反转迁移到整数反转时处理全部数位,并检查有符号整数范围。
先说清契约,再独立实现进入本单元 ↗
UNIT 02数位与进位

#66 加一

保存的状态
数位数组、当前下标与进位。
查询与更新
从最低位向左传播进位,进位消失后可结束。
正确性契约
当前位置右侧已成为最终结果,剩余影响仅由进位表示。
边界与增量
连续的 9 与最高位新增数位;本题不需要哈希。
迁移 · #67 二进制求和二进制求和增加第二个输入和不同长度,基数从 10 改为 2。
先说清契约,再独立实现进入本单元 ↗
UNIT 03存在与索引

#217 存在重复元素

保存的状态
集合保存已经扫描过的元素值。
查询与更新
先判断当前值是否已出现,再记录当前值。
正确性契约
集合恰好表示当前元素之前的历史值。
边界与增量
空历史不产生重复,不能先写入再查询自己。
迁移 · #219 存在重复元素 II重复元素 II 要记录最近索引,并检查索引差是否不超过 k。
先说清契约,再独立实现进入本单元 ↗
UNIT 04存在与索引

#1 两数之和

保存的状态
映射保存历史元素值对应的索引。
查询与更新
先查询目标补数,再写入当前值和索引。
正确性契约
候选搭档来自之前的元素,不会让同一索引匹配自己。
边界与增量
两个相同数可以来自不同索引;重复键仍须保证合法配对。
迁移 · #167 两数之和 II - 输入有序数组有序输入可改用相向指针,利用单调性排除整批数对。
先说清契约,再独立实现进入本单元 ↗
UNIT 05频次与一致性

#242 有效的字母异位词

保存的状态
字符到剩余数量的频次表。
查询与更新
建立第一个字符串的库存,再消耗第二个字符串的字符。
正确性契约
处理过程中,表中数量表示尚未匹配的字符余额。
边界与增量
长度不同或消耗不足即失败;数量不能只用存在性代替。
迁移 · #383 赎金信赎金信允许库存剩余,条件从数量相等改为库存足够。
先说清契约,再独立实现进入本单元 ↗
UNIT 06频次与一致性

#205 同构字符串

保存的状态
两个方向的字符映射。
查询与更新
检查历史配对是否冲突,再同时建立正向与反向关系。
正确性契约
每个源字符只对应一个目标字符,目标字符也不能被不同源占用。
边界与增量
仅维护单向映射不能保证一一对应。
迁移 · #290 单词规律单词规律把目标字符改成单词,仍需双向一致性。
先说清契约,再独立实现进入本单元 ↗
UNIT 07等价类与状态图

#49 字母异位词分组

保存的状态
规范化字符频次键到单词列表的映射。
查询与更新
为每个单词构造稳定的等价类键,再归入对应分组。
正确性契约
同组单词的字符数量完全相同,不同组的键不同。
边界与增量
键必须可哈希,不能把不同字符或频次混在一起。
迁移 · #890 查找和替换模式模式匹配的等价性改为首次出现位置结构,而非字符数量。
先说清契约,再独立实现进入本单元 ↗
UNIT 08等价类与状态图

#128 最长连续序列

保存的状态
所有不同数值组成的集合。
查询与更新
仅从不存在前驱的数值出发,沿连续后继扩展。
正确性契约
每段连续整数链只从唯一的最小值开始处理。
边界与增量
重复值不增加长度,输入中的相邻位置不等于数值连续。
迁移 · #674 最长连续递增序列连续递增序列依赖原数组的相邻顺序,因此改为线性段扫描。
先说清契约,再独立实现进入本单元 ↗
UNIT 09等价类与状态图

#202 快乐数

保存的状态
当前整数状态与已经出现过的状态集合。
查询与更新
生成各位平方和;到达 1 则成功,遇到历史状态则检测到循环。
正确性契约
每次转换都是确定性的,重复状态意味着未来轨迹重复。
边界与增量
记录的是完整数值状态,而非某一个数位。
迁移 · #141 环形链表环形链表把数值转换换成 next 后继,可用快慢指针检测循环。
先说清契约,再独立实现进入本单元 ↗
UNIT 10组合与多维约束

#454 四数相加 II

保存的状态
左侧两个数组的配对和及其出现频次。
查询与更新
先统计左半配对和,再查询右半配对和所需的相反数。
正确性契约
每次命中增加的是索引组合数量,而非只增加一个不同数值。
边界与增量
重复值仍代表不同索引组合;计数和去重是不同任务。
迁移 · #15 三数之和三数之和要求返回唯一数值三元组,需要排序与去重。
先说清契约,再独立实现进入本单元 ↗
UNIT 11组合与多维约束

#560 和为 K 的子数组

保存的状态
当前前缀和与历史前缀和频次。
查询与更新
查询与当前前缀相差 k 的历史数量,再记录当前前缀。
正确性契约
历史表包含虚拟零前缀及当前元素之前的所有前缀。
边界与增量
负数使普通滑窗失效;先记录当前前缀会误计空区间。
迁移 · #974 可被 K 整除的子数组整除子数组改为按余数分组,统一负数余数的表示。
先说清契约,再独立实现进入本单元 ↗
UNIT 12组合与多维约束

#36 有效的数独

保存的状态
每一行、每一列、每一宫已经出现的数字。
查询与更新
跳过空格,同时检查三个范围,再同步记录数字。
正确性契约
所有已处理的非空格在行、列、宫中均无重复。
边界与增量
校验已有数字不代表棋盘一定能求解。
迁移 · #37 解数独解数独增加候选选择与撤销,从静态校验升级为约束搜索。
先说清契约,再独立实现进入本单元 ↗
1. 为什么需要哈希
2. 哈希函数
3. 冲突
4. set 与 dict
5. 复杂度与边界
6. 题型触发信号
键 key例如整数 18、字符串 "apple"、用户ID等。
→
哈希函数 hash(key)把任意键转换为一个可用于定位的整数。
→
桶 bucket根据哈希值进入某个存储位置。
h(18) = 18 mod 7 = 4
教学哈希表:7 个桶,链式保存冲突元素当前为空
当前 key18
hash 值4
目标桶4
是否冲突否
当前元素数0

你需要带进刷题阶段的哈希心智模型

哈希的本质不是“背 set 或 dict”,而是:当问题反复询问某个键的历史信息时,用哈希结构把历史压缩成可快速查询的状态。根据任务不同,可以保存是否出现、索引、频次、分组列表或其他附加信息。

key → hash → bucket 冲突必须处理 set:只存键 dict:键→信息 平均 O(1) 最坏并非 O(1)
下一单元:LeetCode #217 存在重复元素 把“判断某个值以前是否出现过”编译为 Python set。
进入 Unit 01 →