1. 滑动窗口基本思想
滑动窗口就是快慢指针问题,快指针走一步,慢指针走一步,维护窗口的大小。
下图有大小为3的滑动窗口移动示例。
- 窗口:窗口是left和right之间的元素,也可以理解为一个区间。窗口的大小可能固定,也可能变化,如果是固定大小,需要先确定窗口是否越界,再处理逻辑。如果是大小不固定,就需要先判断是否满足要求,调整窗口,再处理逻辑。
- 滑动:说明窗口是移动的,事实上是两个指针left和right变量在移动,而不是序列中的元素移动,当变量移动的时候,其中间的元素会发生变化,因此就有了不断滑动的效果。
根据窗口的大小是否固定,可以有两种类型的题:
- 固定窗口:一般会求窗口内元素最大、最小、平均值、和最大、最小等类型问题。
- 窗口是可变的:一般是求序列中最大。最小窗口,比如最大、最小连续序列。
2. 子数组最大平均数
本题是固定窗口问题,LeetCode643 给定n个整数,找出平均数最大且长度大小为k的连续子数组,并输出该最大平均数。其中 1 <= k <= nums.length <= 10^5.
两步操作
- 维护窗口大小并移动。
- 在窗口中求平均值,与上次的比较返回最大值。
代码示例:
public static double findMaxAverage(int[] nums, int k) {
int len = nums.length;
int windowSum = 0;
if (k > nums.length || nums.length < 1 || k < 1) {
return 0;
}
//第一步 先求第一个窗口的和
for (int i = 0; i < k; i++) {
windowSum += nums[i];
}
//第二步: 遍历,每次右边增加一个,左边减去一个,重新计算窗口最大平均值
int res = windowSum;
for (int right = k; right < len; right++) {
windowSum += nums[right] - nums[right - k];
res = Math.max(res, windowSum);
}
return (double) res / k;
}
3. 最长连续递增序列
窗口大小不固定问题,LeetCode674 给定一个未经排序的整数数组,找到最长且连续递增的子序列,并返回该序列的长度。
示例:{1,3,5,7,8,92}
思路
- 如果遍历到的元素比左边的元素大,right就增加。
- 否则就将left跳到right的位置作为起始位置,重新开始计算。
public static int findLength(int[] nums){
int left = 0, right = 0;
int res = 0;
while (right < nums.length){
//1.右侧元素比左侧元素大,right++
//2.否则,重新记录left位置
if (right > 0 && nums[right - 1] >= nums[right]){
left = right;
}
right ++;
res = Math.max(res , right-left);
}
return res;
}