滑动窗口—长度最小的子数组
describe
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
解析
nums = [2,3,1,2,4,3] s = 7,
本题使用滑动窗口解决, 对于vector 数组, 将right 指针在vector 上不断右移,直到cnt 计数上维护的窗口内的总和大于输入给定的s 值,对应if 语句if(cnt > = s) , 此时说明找到一个粗糙的窗口, 如right 指向4
进入while(cnt > = s)的循环, 对粗糙的窗口进行优化, left 指针不断左移, 跳出时cnt < s , 如left 指向3
计算区间长度并更改答案即可.
进入到下一次循环, 找到下一个粗糙的窗口.
c++代码
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int cnt=0;
int right=0,left=0;
int ans=INT_MAX;
while(right<nums.size()){
cnt+=nums[right];
right++;
if(cnt>=s){
while(cnt>=s){
cnt-=nums[left];
left++;
}
ans=min(ans,right-left+1);
}
}
return ans==INT_MAX?0:ans;
}
};
!!!
- 写题解时,对right++ 和 left++ 以及更新ans 代码所在位置的关系有了进一步了解(其实并没有 ), 由于维护的窗口是左闭右开的, 所以有很多的细节问题需要处理, 虽然能够得到答案, 但其实是计算出的, 窗口逻辑上存在一点问题.
- 如果将right++ 写到if语句块之下, 就是左闭右闭区间, 但是left 此时应指向前一位才为当前窗口的可行解.可以写个暂时的值指向前一位置即可, 但是感觉较麻烦.
- 所以最后既然left跳出的时候是不满足条件的, 于是便放弃先粗糙窗口再优化的思路(其实是我太笨了呜呜)
改为先找到一个粗糙窗口, 接着记录为暂时的可行解, 再使用left 破坏当前解, 寻找出下一个可行的解.
将ans=min(ans,right-left+1);移动到while循环内部首句即可. - 寻找一个最小的窗口与寻找一个最大的窗口, 在细节上有许多的不同!
滑动窗口-----绝对差不超过限制的最长连续子数组
describe
给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。
如果不存在满足条件的子数组,则返回 0 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例
示例 1:
输入:nums = [8,2,4,7], limit = 4
输出:2
解释:所有子数组如下:
[8] 最大绝对差 |8-8| = 0 <= 4.
[8,2] 最大绝对差 |8-2| = 6 > 4.
[8,2,4] 最大绝对差 |8-2| = 6 > 4.
[8,2,4,7] 最大绝对差 |8-2| = 6 > 4.
[2] 最大绝对差 |2-2| = 0 <= 4.
[2,4] 最大绝对差 |2-4| = 2 <= 4.
[2,4,7] 最大绝对差 |2-7| = 5 > 4.
[4] 最大绝对差 |4-4| = 0 <= 4.
[4,7] 最大绝对差 |4-7| = 3 <= 4.
[7] 最大绝对差 |7-7| = 0 <= 4.
因此,满足题意的最长子数组的长度为 2 。
示例 2:
输入:nums = [10,1,2,4,7,2], limit = 5
输出:4
解释:满足题意的最长子数组是 [2,4,7,2],其最大绝对差 |2-7| = 5 <= 5 。
示例 3:
输入:nums = [4,2,2,2,4,4,2,2], limit = 0
输出:3
解析
c++代码
我们只需要维护一个滑动窗口, 根据窗口里的最大值与最小值, 与limit 比较即可.
可以通过multiset 作为窗口的数据结构.
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
int left=0,right=0;
int ans=0;
multiset<int> mtset;
//枚举right
while(right < nums.size()){
//进入窗口中
mtset.insert(nums[right]);
//检查窗口
while(*mtset.rbegin() - *mtset.begin() > limit){
mtset.erase(mtset.find(nums[left++]));
}
//更新窗口大小.
ans = max(ans,right - left + 1);
right++;
}
return ans;
}
};
!!!
这种窗口的书写习惯得养成, 滑动窗口的代码思维还不够
while(right<size()){
insert(right);
while(条件){
erase(left));
left++;
}
ans = max(ans,right-left+1);
right++;
}
right为主动移动, 而left 为被动移动, 用ans 不断的记录窗口的大小.