滑动窗口



滑动窗口—长度最小的子数组

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;
    }
};


!!!

  1. 写题解时,对right++ 和 left++ 以及更新ans 代码所在位置的关系有了进一步了解(其实并没有 ), 由于维护的窗口是左闭右开的, 所以有很多的细节问题需要处理, 虽然能够得到答案, 但其实是计算出的, 窗口逻辑上存在一点问题.
  2. 如果将right++ 写到if语句块之下, 就是左闭右闭区间, 但是left 此时应指向前一位才为当前窗口的可行解.可以写个暂时的值指向前一位置即可, 但是感觉较麻烦.
  3. 所以最后既然left跳出的时候是不满足条件的, 于是便放弃先粗糙窗口再优化的思路(其实是我太笨了呜呜)
    改为先找到一个粗糙窗口, 接着记录为暂时的可行解, 再使用left 破坏当前解, 寻找出下一个可行的解.
    将ans=min(ans,right-left+1);移动到while循环内部首句即可.
  4. 寻找一个最小的窗口与寻找一个最大的窗口, 在细节上有许多的不同!

滑动窗口-----绝对差不超过限制的最长连续子数组

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 不断的记录窗口的大小.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值