LeetCode1438. 绝对差不超过限制的最长连续子数组

力扣

 

解题思路:

1.滑动窗口 + 有序序列

我们可以枚举每一个位置作为右端点,找到其对应的最靠左的左端点,满足区间中最大值与最小值的差不超过 limit。

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

为了方便统计当前窗口内的最大值与最小值,我们可以使用平衡树。

① 使用滑动窗口保持符合条件的子数组,记录最长长度
② 怎样确定子数组是否符合条件,需要知道两个关键数据
 2.1  子数组中的最大值
 2.2  子数组中的最小值
③ 需要对滑入窗口的数据记录,滑出的数据删除,并且使这些记录方便的算出最大值和最小值
3.1  使用 map / multiset 可以在滑入滑出的时候方便的增减对应数据
3.2  同时 map / multiset 本身是有序的,可以方便的找出最大值最小值

作者:ikaruga
链接:https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/solution/longest-continuous-subarray-by-ikaruga/
来源:力扣(LeetCode)

                        

代码:

class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) 
    {
       multiset<int> s; //有序排列,底层是平衡树,支持重复的节点
       int ans = 0;
       int j = 0;
       int sz = nums.size();

       for(int i= 0 ; i < sz ;++i) //i相当于右指针 j相当于左指针
       {
           s.insert(nums[i]);

           while(*s.rbegin() - *s.begin() > limit) //不满足条件的元素从 set中删除
           {
               s.erase(s.find(nums[j++]));
           }

           ans = max(ans , i-j+1); 
       }

       return ans;
    }
};

                

2.滑动窗口+ 单调队列

①.创建两个双端队列queue

② 这两个队列一个为单调增队列(队头元素值最小),一个为单调减队列( 队头元素值最大 )

③ 当滑动窗口右端要新加入一个元素的时候,分别放入单调增和单调减队列中 :
   (1)放入单调增队列 :  如果当前放入元素比单调增队列的队尾元素还要大,就把队尾元素依次出队,直到前面的元素比当前要放入的元素大为止。
   (2) 放入单调减队列 :  如果当前放入的元素比单调减队列的队尾元素还要小,就把队尾元素依次出队,直到前面的元素比当前要放入的元素小为止

④ 以上的步骤可以保证单调增队列的首元素永远是当前滑动窗口的最大值,单调减队列的首元素是当前滑动窗口的最小值

⑤. 如果当前滑动窗口内的最大值减去最小值得到的结果比限制值要大,那么就需要将滑动窗口的左端值移出滑动窗口,然后继续判断最当前滑动窗口最大值减去最小值是否大于限制值,如果大于就重复第五步。

                                

图片来自:花花酱

                 

代码:

class Solution {
public:
    int longestSubarray(vector<int>& nums, int limit) 
    {
       deque<int> max_queue; //记录最大值的队列
       deque<int> min_queue; //记录最小值的队列

       int ans = 0 ;
       int sz = nums.size();

       int l = 0; //左边界
       for(int r = 0 ; r < sz ;++r) //r 右边界
       {
           //新元素比队尾元素大
          while(!max_queue.empty() && max_queue.back() < nums[r])
          max_queue.pop_back();
          
          //新元素比队尾元素小
          while(!min_queue.empty() && min_queue.back() > nums[r])
          min_queue.pop_back();
          
          //新元素入队
          max_queue.push_back(nums[r]);
          min_queue.push_back(nums[r]);

          //如果当前滑动窗口内的最大值减去最小值得到的结果比限制值要大,
          //那么就需要将滑动窗口的左端值移出滑动窗口,
          //然后继续判断最当前滑动窗口最大值减去最小值是否大于限制值
          while(max_queue.front() - min_queue.front() > limit)
          {
              if(max_queue.front() == nums[l])
              max_queue.pop_front();

              if(min_queue.front() == nums[l])
              min_queue.pop_front();

              ++l;

          }

            ans = max(ans, r - l + 1);

       }

       return ans;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值