不定长滑动窗口:让元素先进窗口,然后根据条件判断是否需要缩小窗口长度(窗口左端点右移,右端点不动),来求解问题。不定长滑动窗口最主要的是找到缩小窗口的临界条件。解题方式基本与定长滑动窗口解题思路一致。
解题思路:
以此题为例,题目要求找出数组中满足其总和大于等于 target
的长度最小的子数组,建立滑动窗口,窗口内的元素就是一个子数组,当窗口右端点到达某一个值时,窗口内元素总和减去窗口左端点的值仍然大于等于目标值 targe 时,因为数组是正整数的数组,如果窗口右端点继续往右走,那后续肯定都大于目标值 targe ,而我们要找的是长度最小的子数组,所以此时窗口右端点没有必要往右走,应该让窗口左端点往右走,以此来缩小窗口长度,同时保证窗口中元素和都大于等于目标值targe,直到找到满足需求的最小子数组的长度,再更新信息,然后继续控制窗口往右移,直至遍历完数组就找了数组中满足其总和大于等于 target
的长度最小的子数组。
将上述思想转化为代码:
- 定义变量:sum记录窗口中的元素累加和;left记录窗口左端点;循环遍量right记录窗口右端点;min来记录窗口长度,即子数组的长度;min赋一个极大值:Integer.MAX_VALUE。
- 遍历数组,建立窗口。for循环遍历,循环条件为窗口右端点是否到达数组最右边,即right < nums.length ,然后通过 进窗口-->判断是否需要缩小窗口长度(出窗口)-->更新信息 来求解。
- 进窗口:当元素进入窗口时,我们要记录当前窗口中的元素累加和,即sum+=nums[right]。
- 判断是否需要缩小窗口长度:当窗口中的元素累加和sum减去窗口左端点的值num[left]仍然大于等于目标值targe时,缩小窗口长度,因为不知道窗口需要缩小几次,所以用while。缩小窗口前先让 sum-=num[left] ,再让eft++即可。判断是否需要缩小窗口的条件为 sum-nums[left] >= targe 。因为不知道窗口需要缩小几次,所以用while循环。
- 更新信息:更新信息前我们应判断 sum>= targe,true再更新信息。min取min和满足条件的当前窗口的长度两个的较小值即可,注意此窗口的长度为 right-left+1 ,要加1是因为当right和left指向同一个元素时,窗口长度为1而不是0;
public static int minSubArrayLen(int target, int[] nums) {
int min = Integer.MAX_VALUE;
int sum = 0;
int left = 0;
for(int right = 0; right < nums.length; right++){
// 进窗口
sum += nums[right];
// 判断是否需要缩小窗口长度
while(sum - nums[left] >= target){
sum -= nums[left];
left++;
}
// 更新信息
if (sum >= target) {
min = Math.min(min, right - left + 1);
}
}
return sum>=target?min:0;
}