1. 为什么我们需要尺取法(滑动窗口算法)
第一次听到"尺取法"这个名词时,我也是一头雾水。直到看到它的另一个名字——滑动窗口算法,才恍然大悟。这个算法就像一把可以伸缩的尺子,在数组或序列上滑动,通过动态调整窗口的左右边界[l, r]来高效解决问题。
1.1 从实际问题看暴力解法的局限
让我们通过洛谷P1147这道经典题目来理解尺取法的价值。题目要求找出所有连续自然数段,使其和等于给定的正整数M。比如M=10000时,1998到2002这五个连续数的和正好是10000。
最直观的暴力解法是:
- 枚举所有可能的区间起点l
- 对于每个l,枚举所有可能的终点r(r>l)
- 计算区间[l,r]的和,判断是否等于M
这种解法的时间复杂度高达O(m³)。即使使用前缀和优化,也只能降到O(m²)。当M达到2,000,000时,这样的效率显然无法接受。
1.2 数学分析揭示优化空间
通过数学分析可以发现,对于连续自然数序列:
- 最大右边界r不超过(m+1)/2
- 子区间数量级为O(m²)
这意味着我们需要一种更聪明的方法来避免不必要的计算。这正是尺取法大显身手的地方。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 尺取法的核心原理与特性
2.1 滑动窗口的基本思想
尺取法的核心在于维护一个动态变化的窗口,通过调整左右边界来高效搜索解空间。其关键特性包括:
- 窗口初始化:通常从序列起点开始,l=r=1
- 窗口移动规则:
- 当当前和小于目标值时,右移r扩大窗口
- 当当前和大于目标值时,右移l缩小窗口
- 当等于目标值时,记录解并继续搜索
2.2 单调性保证效率
尺取法高效的关键在于序列的单调性。对于连续自然数序列:
- 扩大窗口(增加r)必然增大和
- 缩小窗口(增加l)必然减小和
这种单调性确保了:
- 不需要回溯已经检查过的区间
- 每个元素最多被访问两次(进入和离开窗口)
- 时间复杂度从O(m²)降至O(m)
2.3 算法可视化演示
以M=10为例,看看尺取法的实际工作过程:
- 初始状态:[1] → sum=1 <10
- 扩大窗口:[1,2] → sum=3 <10
- 继续扩大:[1,2,3] → sum=6 <10
- 继续扩大:[1,2,3,4] →
