CPH-第八章 均摊分析
均摊分析思想:针对单次操作耗时不均、但整体操作总次数可控的算法,不纠结单次操作的最坏复杂度,而是估算全部操作的总时间开销,证明平均到每次操作的复杂度足够低。
- 很多算法单次操作看似耗时很高,但从全局看每个元素只会被处理有限次。
- 双指针、单调栈、单调队列都是这一思想的典型产物,是处理数组问题的高频高效技巧。
8.1 双指针法(Two pointers method)
核心思想
- 用两个指针遍历数组,两个指针都只向单一方向移动(不会回退),因此每个指针在整个算法过程中最多移动 \(n\) 步,总操作量为 \(O(n)\),均摊到每一步都是常数时间。
子数组和问题
-
给定全为正整数的数组和目标和 \(x\),判断是否存在连续子数组的和恰好等于 \(x\)。
- 算法流程:维护左右指针表示子数组区间;左指针每向右移动一步,右指针就尽可能向右延伸,只要子数组和不超过 \(x\)。若和恰好等于 \(x\) 则找到解。
- 复杂度分析:右指针全程只向右不向左,总移动步数不超过 \(n\);左指针也仅移动 \(n\) 步。因此总时间复杂度为 \(O(n)\)。
2SUM 问题
- 给定数组和目标和 x,找出两个元素使其和为 x。
- 先将数组排序,左指针指向数组开头、右指针指向数组末尾;
- 左指针逐步右移,右指针同步左移,使两数之和向目标值靠近。
- 复杂度分析:排序耗时 \(O(n \log n)\),双指针遍历耗时 \(O(n)\),整体复杂度 \(O(n \log n)\)。
- 延伸:基于相同思想,3SUM 问题可以在 \(O(n^2)\) 时间内求解。
8.2 最近更小元素(Nearest smaller elements)
-
对数组中每个元素,找到它左侧第一个比它小的元素(不存在则标记为空)。
-
算法:单调栈
-
从左到右遍历数组,维护一个元素值单调递增的栈。
-
不断弹出栈顶所有大于等于当前元素的元素。
-
此时栈顶元素就是当前元素的「最近更小元素」。
-
将当前元素压入栈中。
-
-
均摊复杂度分析
-
每个数组元素恰好入栈一次、最多出栈一次,整个算法过程中栈的弹出操作总次数不超过 \(n\)。
-
因此尽管单次遍历可能弹出多个元素,但全部操作总次数为 \(O(n)\),均摊时间复杂度为 \(O(n)\)。
-
8.3 滑动窗口最小值(Sliding window minimum)
-
固定大小的窗口从数组左端向右滑动,输出每个窗口位置对应的最小值。
-
算法:单调队列
- 维护一个元素值单调递增的双端队列,队首始终是当前窗口的最小值:
- 窗口右移加入新元素时,从队尾不断弹出所有大于等于新元素的元素,再将新元素加入队尾;
- 检查队首元素是否已滑出窗口,若滑出则从队首移除;
- 此时队首元素即为当前窗口的最小值。
-
均摊复杂度分析
- 每个元素恰好入队一次、最多出队一次,所有入队、出队操作的总次数为 \(O(n)\)。
- 因此算法整体均摊时间复杂度为 \(O(n)\)。
浙公网安备 33010602011771号