LeetCode 209. 长度最小的子数组
滑动窗口,初始时left和right都指向第一个位置。如果和小,那么right右移。如果和大于等于,满足条件形成了子数组,left右移,缩小左边界,寻找新的结果。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int len=nums.length;
int left=0,right=0;
int min=Integer.MAX_VALUE;//记录最小子数组的大小
int sum=0;
while(right<len){
sum+=nums[right];//将数字加入子数组
//问题求:其总和大于等于 target
while(sum>=target){//找到一个子数组[left,right]
min=Math.min(min,right-left+1);
sum-=nums[left];
left++;
}
//sum<target
right++;
}
return min==Integer.MAX_VALUE?0:min;//无结果,返回0
}
}
什么时候使用滑动窗口?
维护一个可以滑动的窗口,在数组或字符串等线性数据结构上进行高效的操作。
1. 子数组或子字符串问题
- 问题特征:当问题要求在一个数组或字符串中找出满足特定条件的连续子数组或子字符串时,滑动窗口往往是一个不错的选择。例如,需要找出和满足一定条件(如和大于等于某个值、和等于某个值)的最短或最长连续子数组,或者找出包含特定字符的最短或最长连续子字符串等。
- 示例题目
- 209. 长度最小的子数组:给定一个含有
n
个正整数的数组和一个正整数target
,找出该数组中满足其和≥ target
的长度最小的连续子数组。可以使用滑动窗口不断调整窗口的大小和位置,找到满足条件的最小子数组长度。 - 76. 最小覆盖子串:给定一个字符串
s
和一个字符串t
,在s
中找到包含t
中所有字符的最小子串。通过滑动窗口,在s
上移动窗口,不断调整窗口的左右边界,找到满足条件的最小子串。
- 209. 长度最小的子数组:给定一个含有
2. 固定大小窗口问题
- 问题特征:问题要求处理固定大小的连续子数组或子字符串。在这种情况下,可以使用一个固定大小的滑动窗口在数据结构上滑动,依次处理每个窗口内的元素。
- 示例题目
- 剑指 Offer 57 - II. 和为 s 的连续正数序列:输入一个正整数
target
,输出所有和为target
的连续正整数序列(至少含有两个数)。可以使用一个固定大小的滑动窗口,从较小的窗口开始,逐步调整窗口大小,找到所有满足条件的连续正整数序列。 - 643. 子数组最大平均数 I:给定一个由
n
个元素组成的整数数组nums
和一个整数k
,找出平均数最大且长度为k
的连续子数组,并输出该最大平均数。使用固定大小为k
的滑动窗口在数组上滑动,计算每个窗口内元素的和,进而得到最大平均数。
- 剑指 Offer 57 - II. 和为 s 的连续正数序列:输入一个正整数
3. 区间统计问题
- 问题特征:需要统计满足特定条件的区间数量。滑动窗口可以通过动态调整窗口的边界,高效地统计符合条件的区间。
- 示例题目
- 992. K 个不同整数的子数组:给定一个正整数数组
A
,如果A
的某个子数组中不同整数的个数恰好为K
,则称A
的这个连续、不一定独立的子数组为好子数组。求A
中好子数组的数目。可以使用两个滑动窗口分别统计不同整数个数小于等于K
和小于等于K - 1
的子数组数量,然后相减得到不同整数个数恰好为K
的子数组数量。
- 992. K 个不同整数的子数组:给定一个正整数数组
4. 字符串匹配问题
- 问题特征:在字符串匹配过程中,需要对连续的子字符串进行操作和判断。滑动窗口可以在字符串上滑动,检查每个窗口内的子字符串是否满足匹配条件。
- 示例题目
- 438. 找到字符串中所有字母异位词:给定两个字符串
s
和p
,找到s
中所有p
的异位词的子串,返回这些子串的起始索引。使用滑动窗口在s
上滑动,比较窗口内的字符频率和p
的字符频率是否相同,从而找出所有的异位词子串。
- 438. 找到字符串中所有字母异位词:给定两个字符串
判断是否使用滑动窗口的一般思路
- 连续子结构:如果问题关注的是连续的子数组、子字符串等结构,那么可以考虑滑动窗口。
- 动态调整:当需要根据当前窗口内的元素状态动态调整窗口的大小和位置时,滑动窗口通常是有效的方法。
- 优化复杂度:如果使用暴力解法的时间复杂度较高(如 O ( n 2 ) O(n^2) O(n2) 或更高),而滑动窗口可以将时间复杂度优化到 O ( n ) O(n) O(n),那么滑动窗口是一个值得尝试的选择。