LeetCode 1438 绝对差不超过限制的最长连续子数组(滑动窗口,单调队列)

题目一看就是采用滑动窗口来解决,之所以记录一下是想复习一下单调队列的语法逻辑。
题干如下:
在这里插入图片描述
我们可以枚举每一个位置作为右端点,找到其对应的最靠左的左端点,满足区间中最大值与最小值的差不超过 limit。

注意到随着右端点向右移动,左端点也将向右移动,于是我们可以使用滑动窗口解决本题。

这里我们需要一个数据结构来存储滑动窗口中的元素,并且需要对滑动窗口的元素进行排序,在C++中,map和set就有这样的功能,考虑到滑动窗口中的元素有可能重复,所以这里采用C++ STL中的multiset数据结构。multiset允许出现重复元素,并且具有排序功能,通过multiset.begin()和multiset.end()-1就可以访问到最大最小元素了。

方法一:滑动窗口+有序集合

代码如下:

class Solution {
public:  //参考官方解答,滑动窗口
    int longestSubarray(vector<int>& nums, int limit) {
        multiset<int> st;   //有序集合
        int n = nums.size();
        int left = 0, right = 0; //滑动窗口
        int res = 0;
        while(right<n){
            st.insert(nums[right]);
            while(*(--st.end()) - *st.begin() > limit){  //条件判断
                st.erase(st.find(nums[left]));
                left++;
            }
            res = max(res,right - left + 1);  //实时更新
            right++;
        }
        return res;
    }
};

方法二:滑动窗口+单调队列

在方法一中,我们仅需要统计当前窗口内的最大值与最小值,因此我们也可以分别使用两个单调队列解决本题。

在实际代码中,我们使用一个单调递增的队列 queMin 维护最小值,一个单调递减的队列queMax 维护最大值。这样我们只需要计算两个队列的队首的差值,即可知道当前窗口是否满足条件。

代码如下:

class Solution {
public: //力扣官方,滑动窗口+单调队列
    int longestSubarray(vector<int>& nums, int limit) {
        int n = nums.size();
        deque<int> queMin, queMax;  //单调队列
        int left = 0, right = 0;  //滑动窗口
        int res = 0;
        while(right < n){
            while(!queMax.empty()&&queMax.back() < nums[right])  //单调递减队列
                queMax.pop_back();
            while(!queMin.empty()&&queMin.back() > nums[right])  //单调递增队列
                queMin.pop_back();
            queMin.push_back(nums[right]);
            queMax.push_back(nums[right]);
            while(!queMax.empty()&&!queMin.empty()&&queMax.front() - queMin.front() > limit){ //条件判断
                if(queMin.front() == nums[left])
                    queMin.pop_front();
                if(queMax.front() == nums[left])
                    queMax.pop_front();
                left++;
            }
            res = max(res,right - left + 1);
            right++;
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值