Skip to content

Latest commit

 

History

History
88 lines (50 loc) · 6.65 KB

README.md

File metadata and controls

88 lines (50 loc) · 6.65 KB

AlgorithmNote

本项目记录算法学习笔记。总结每道题的核心思路、算法实现与正确性证明,提炼可复用的算法设计思想。

一、算法笔记

核心思想:二分查找划分边界。

划分思路本身比较简单,难点在于统一处理边界条件并保证算法正确性。

  1. 奇偶统一:统一使用 (m+n+1)//2 确定划分位置,仅在返回中位数时区分奇偶。
  2. 数组边界:明确变量表示划分位置,而非数组下标;使用正负无穷大作为哨兵处理空区间。
  3. 循环不变量:利用条件的单调性进行二分查找,通过循环不变量证明不会遗漏目标位置,且最终结果不会被覆盖。

可复用经验: 明确变量含义,统一处理特殊情况,利用循环不变量证明算法正确性。

核心思想: 使用 set 加速成员查询,并仅从连续序列的最小元素开始向后检查,避免重复遍历。

  1. 避免不必要的约束:只需要保证整个算法最终得到正确结果,不必为每个中间步骤添加不必要的约束。
  2. 先求解,再优化:在有性能要求的问题上,先找到简单思路,再分析性能瓶颈并逐步优化。

核心思想: 使用双指针将非零元素按原顺序写入数组前部,再将剩余位置填零。

核心思想: 利用双指针维护左右两侧的最大高度,每次处理最大高度较小的一侧,逐步确定各位置的接水量。

  1. 从确定性出发:先解决能够确定结果的边界位置,再逐步扩展到未解决区域。
  2. 利用问题性质推进:根据接水量由左右最大高度的较小值决定这一性质,选择可以安全处理的一侧。

核心思想: 将问题分解为以不同位置为起点的子问题,再利用滑动窗口复用相邻子问题的计算结果,避免重复搜索。

  1. 解空间分解:按照某一维度划分候选解,分别求出局部最优解,再合并得到全局最优解。
  2. 增量计算:利用相邻子问题之间的关联,复用已有计算结果,避免重复计算。

核心思想: 通过解空间分解,将问题转化为统计每个起点或终点对应的合法子数组数量。按终点枚举更适合从左向右遍历:利用前缀和与哈希表维护历史信息,即可直接统计当前终点对应的合法起点,无需重复扫描后续元素,将时间复杂度从 $O(n^2)$ 优化至平均 $O(n)$。按起点枚举也可以通过反向遍历实现相同复杂度。

核心思想: 通过解空间分解,将问题转化为判断每个固定长度的子串是否为字母异位词。利用滑动窗口复用相邻子问题的字符频次,并通过 diff 记录频次不匹配的字符种类数,采用新贡献减去旧贡献的方式增量更新,将每次窗口判断优化为 $O(1)$。

核心思想: 通过解空间分解,将问题规约为求解每个固定长度窗口的最大值。利用支配关系进行候选剪枝:当新元素在数值和有效期上均不劣于较早元素时,可以安全淘汰较早元素。使用单调队列增量维护最大值候选,将时间复杂度从 $O(nk)$ 优化至 $O(n)$。

  1. 支配关系与候选剪枝:根据数值优势和位置优势,证明被支配的元素不可能再成为必须保留的最大值候选。
  2. 增量维护:通过队首删除过期元素、队尾淘汰被支配元素,实现窗口最大值的高效更新。
  3. 循环不变量:不变量只需在每轮完整迭代结束时成立即可。

核心思想: 通过解空间分解,将问题规约为寻找每个起点对应的最短合法子串。利用覆盖条件的单调性,通过滑动窗口使左右指针单向移动,避免枚举所有子串;使用字符需求表 need 和缺失计数 missing 增量维护覆盖状态,将时间复杂度从朴素枚举的 $O(n^2)$ 级别优化至 $O(|s|+|t|)$。

核心思想: 排序 + 贪心。朴素解法中,当前合并区间的最终结果依赖于所有剩余区间,需要反复检查。通过按左端点排序建立单调性,使得当前区间一旦与下一个区间不重叠,就必然与所有后续区间不重叠,从而实现局部解与剩余区间的解耦。局部解可以安全确定,无需回溯,将反复扫描转化为一次线性扫描。一般性的算法思路是:通过引入某种结构(排序、单调性、边界约束等),将原本相互依赖的子问题转化为可以独立确定的局部问题。

二、通用算法设计思想

核心思想:从初始状态和目标状态出发,通过循环不变量设计状态迁移,再推导具体实现。

以回文链表的反转操作为例,将算法设计分为四个步骤:

  1. 状态定义:明确初始状态与目标状态,提取不同情况的共同结构,统一边界条件。
  2. 不变量设计:根据合法中间状态推导状态变量、初始化和终止条件。
  3. 状态迁移与实现:先设计抽象状态迁移,再根据数据依赖推导具体操作顺序,必要时引入临时变量。
  4. 正确性证明:证明初始化、不变量保持、算法终止及目标达成。

三、算法基础知识

核心内容: 介绍常见渐近复杂度记号的严格数学定义,以及 Python 常用数据结构操作的时间复杂度。

  1. 复杂度记号:理解大 O、大 Ω、大 Θ、小 o、小 ω 等渐近记号及其数学含义。
  2. 数据结构复杂度:掌握 Python list、dict、set 等常用数据结构的典型操作复杂度及适用条件。