滑动窗口算法的核心在于维护一个动态区间,通常用于解决连续子数组或子串的最值问题。这类题目往往有一个关键前提:数组元素多为正整数。这样做的意义在于保证单调性——随着右指针向右移动,窗口内的和只会增加;而左指针向右移动时,和只会减少。这种性质让我们可以安全地收缩窗口而不必担心遗漏更优解。
以 LeetCode 209 长度最小的子数组为例,给定一个包含 n 个正整数的数组和一个正整数 target,找出和大于等于 target 的长度最小的连续子数组。如果不存在符合条件的子数组,返回 0。
实现思路其实很直观。我们定义两个指针 left 和 right,初始都指向数组头部。right 负责不断扩张窗口,累加当前元素到 sum 中。一旦 sum 达到或超过 target,说明当前窗口满足条件,此时记录长度并尝试收缩左边界。只要 sum 依然满足条件,就持续移除 left 位置的元素并移动 left 指针,直到 sum 小于 target。在这个过程中,不断更新最小长度 ans。
具体代码实现如下:
from typing import List
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
ans = n + 1
s = left = 0
for right, x in enumerate(nums):
s += x
while s >= target:
ans = min(ans, right - left + 1)
s -= nums[left]
left += 1
return ans if ans != n + 1 else 0
注意几个细节。初始化 ans 为 n + 1 或者无穷大,是为了方便后续判断是否找到了有效解。循环结束后,如果 ans 仍然是初始值,说明没有符合条件的子数组,应返回 0。另外,while 循环的条件是 s >= target,这保证了我们在找到满足条件的最短前缀后继续尝试缩短。
时间复杂度方面,left 和 right 指针各自最多遍历数组一次,因此整体复杂度为 O(n)。空间上只用了常数个变量,复杂度 O(1)。这是处理此类问题最高效的方案之一。


