Python算法训练序列

双指针前置心智模型 · Unit 00

双指针不是“两个变量”,
而是一条压缩候选空间的路径。

本单元只训练一个核心能力:每次移动指针时,你都必须能指出——哪些候选因此被排除,以及为什么这些候选全部不可能成为答案。

CHAPTER 02 / THE COGNITIVE ATLAS

第 2 章 · 认知梯度全景图

双指针与滑动窗口:用指针的移动与窗口的伸缩,组织有序的搜索过程。

7 个后续单元
贯穿本章的统一框架定义候选空间 → 证明移动安全 → 维护不变量。两个指针的语义决定能排除哪些候选。

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

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

起点 · Unit 00 双指针与窗口的心智模型。先理解状态、操作与不变量,再沿下列路线练习。
  1. 01

    指针角色

    区分镜像比较与稳定写入:相向和同向有不同契约。

  2. 02

    单调性与降维

    用有序关系排除数对,再固定一维处理三元组。

  3. 03

    窗口状态

    把字符频次变成区间状态,区分去重窗口和定长窗口。

  4. 04

    目标与计数

    利用正数和的单调性收缩窗口,再迁移到乘积区间计数。

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

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

UNIT 01指针角色

#125 验证回文串

候选空间
首尾尚未比较的有效字符对。
安全移动
跳过非字母数字字符,再比较两端并同时向内移动。
循环不变量
区间外已经比较的有效字符对都相同。
边界检查
大小写归一;过滤后为空也满足回文。
迁移 · #680 验证回文串 II允许删除一个字符时,第一次冲突需要分别验证跳过左端或右端。
先说清契约,再独立实现进入本单元 ↗
UNIT 02指针角色

#283 移动零

候选空间
已写入的非零前缀与尚未读取的后缀。
安全移动
读指针扫描,非零元素放入写指针位置,再前移写指针。
循环不变量
已写前缀保持非零元素原始相对顺序。
边界检查
最终补零;读写指针不能因零元素同时前进。
迁移 · #27 移除元素移除元素把“零”改为指定值,并返回有效前缀长度。
先说清契约,再独立实现进入本单元 ↗
UNIT 03单调性与降维

#167 两数之和 II

候选空间
有序数组中尚未排除的索引数对。
安全移动
和太小舍弃左端候选,和太大舍弃右端候选。
循环不变量
若存在解,至少一组合法数对仍在当前范围内。
边界检查
两个索引必须不同,题目要求的下标起点需转换。
迁移 · #2824 统计和小于目标的下标对数目统计小于目标的数对时,一次安全移动可以累计整批合法搭档。
先说清契约,再独立实现进入本单元 ↗
UNIT 04单调性与降维

#15 三数之和

候选空间
固定首元素后的有序数对空间。
安全移动
外层固定一个数,内层相向搜索,并跳过重复数值。
循环不变量
每轮内层搜索只处理当前首元素,输出三元组不重复。
边界检查
三索引互异;外层与两端均须处理重复。
迁移 · #16 最接近的三数之和最接近三数和维护全局差值,不能只记录精确命中。
先说清契约,再独立实现进入本单元 ↗
UNIT 05窗口状态

#3 无重复字符的最长子串

候选空间
右端扩展、左端按需收缩的字符串区间。
安全移动
新字符造成重复时,收缩到窗口内重新无重复。
循环不变量
更新最长长度时,窗口内每个字符至多出现一次。
边界检查
集合与最近索引两种表示不同,左端不能倒退。
迁移 · #209 长度最小的子数组最小长度子数组把去重约束换成和达到目标,且改为求最短。
先说清契约,再独立实现进入本单元 ↗
UNIT 06窗口状态

#438 找到字符串中所有字母异位词

候选空间
长度等于模式长度的字符窗口。
安全移动
滑入新字符、滑出旧字符,比较窗口与模式频次。
循环不变量
每次判定时频次仅表示当前定长窗口。
边界检查
模式比文本长时无候选;不能只比较字符集合。
迁移 · #567 字符串的排列字符串的排列从返回所有起点改为找到一个即返回。
先说清契约,再独立实现进入本单元 ↗
UNIT 07目标与计数

#209 长度最小的子数组

候选空间
正数数组中和达到目标的连续区间。
安全移动
先扩张到有效,再持续收缩并记录最短有效长度。
循环不变量
记录答案时当前窗口和达到目标,收缩后仍须重新验证。
边界检查
依赖元素为正数;不存在有效区间时返回规定的空结果。
迁移 · #713 乘积小于 K 的子数组乘积小于 k 改为先恢复合法窗口,再累计以当前右端结尾的区间。
先说清契约,再独立实现进入本单元 ↗
1. 看见候选空间
2. 一次排除一整列
3. 一次排除一整行
4. 错误移动会丢失答案
5. 从O(n²)到O(n)
numbers = [1,2,4,6,8,11],target = 10准备观察
numbers[left]1
+
numbers[right]11
=
current_sum12
12 > 10:当前和偏大

全部候选数对矩阵

尚未排除 当前比较 已证明不可能 真实答案

这一帧到底证明了什么?

循环不变量

如果答案尚未找到,那么至少一个答案仍位于蓝色未排除区域中。

移动的合法性

只有当一整行或一整列都能被证明不可能时,对应端点才可以安全移动。

left / right0 / 5
当前和12
剩余候选15
已排除候选0
路径步数0

Unit 00 最终心智模型

双指针算法的本质不是“从两边开始试数”,而是用两个边界描述尚未排除的候选空间。每次移动都必须伴随一批候选被证明不可能;正确性来自不变量,线性复杂度来自两个边界只沿一个方向移动。

暴力枚举

6个元素产生15个候选数对。一般情况下需要检查约n(n-1)/2个格子。

双指针路径

这里只走了3个状态,每一步删除一整行或一整列。一般情况下left和right总移动次数不超过2n。

(1,11)=12 (1,8)=9 (2,8)=10
下一单元:LeetCode #125 验证回文串

Unit 01 会把“候选区间与安全移动”迁移到字符串镜像比较:无效字符为什么可以跳过、有效字符相等后为什么可以同时收缩两端。