⭐算法入门⭐《队列 - 单调队列》中等02 —— LeetCode 1438. 绝对差不超过限制的最长连续子数组

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了⭐算法入门⭐《队列 - 单调队列》中等02 —— LeetCode 1438. 绝对差不超过限制的最长连续子数组相关的知识,希望对你有一定的参考价值。

🙉饭不食,水不饮,题必须刷🙉

C语言免费动漫教程,和我一起打卡!
🌞《光天化日学C语言》🌞

LeetCode 太难?先看简单题!
🧡《C语言入门100例》🧡

数据结构难?不存在的!
🌳《画解数据结构》🌳

LeetCode 太简单?算法学起来!
🌌《夜深人静写算法》🌌

一、题目

1、题目描述

  给你一个整数数组nums,和一个表示限制的整数 l i m i t limit limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 l i m i t limit limit 。如果不存在满足条件的子数组,则返回 0。
  样例输入: nums = [8,2,4,7], limit = 4
  样例输出: 2

2、基础框架

  • C语言版本 给出的基础框架代码如下:
int longestSubarray(int* nums, int numsSize, int limit){
}

3、原题链接

( 1 ) (1) (1) LeetCode 1438. 绝对差不超过限制的最长连续子数组

二、解题报告

1、思路分析

  1)假设现在有一个连续子数组,要求任意两个元素的绝对差小于等于 limit,就是要求这个连续子数组的 最大值 减去 最小值 小于等于 limit;
  2)考虑两个数的连续子数组,其中下标肯定满足 i < i + 1 i \\lt i+1 i<i+1, 如果 a i ≤ a i + 1 a_i \\le a_{i+1} aiai+1,我们需要求其中的最大值,那么 a i a_i ai 是多余的;
更加明显的, i < i + 1 < i + 2 < i + 3 i \\lt i+1 \\lt i+2 \\lt i+3 i<i+1<i+2<i+3,如果 a i < a i + 1 < a i + 2 < a i + 3 a_i \\lt a_{i+1} \\lt a_{i+2} \\lt a_{i+3} ai<ai+1<ai+2<ai+3 成立的话, a i , a i + 1 , a i + 2 a_i,a_{i+1},a_{i+2} ai,ai+1,ai+2 相对于 a i + 3 a_{i+3} ai+3 来说都是多余的,所以在求最大值时,我们可以维护一个单调递减的队列。
  3)同样,再求最小值的过程中,我们可以维护一个单调递增的队列。
  4)这样,每次插入一个数之前,我们可以通过两个单调队列的队首元素相减,判断是否满足 差值小于等于 limit 这个条件,来选择是否对单调队列中的队首元素进行出队,并且还要比较两个队列的队首元素,将队首小的那个队列再次执行出队。
  5)满足以上两个条件,统计本次 连续子数组 长度,记录最大值就是答案了。

2、时间复杂度

  • 对于每个队列,每个元素只支持最多一次入队和出队,所以时间复杂度为 O ( n ) O(n) O(n)

3、代码详解

/**************************** 顺序表 实现队列 ****************************/
#define DataType int
#define maxn 100005

struct Queue {
    DataType data[maxn];
    int head, tail;
};

void QueueClear(struct Queue* que) {
    que->head = que->tail = 0;
}
void QueueEnqueue(struct Queue *que, DataType dt) {
    que->data[ que->tail++ ] = dt;
}
void QueueDequeueFront(struct Queue* que) {
    ++que->head;
}
void QueueDequeueRear(struct Queue* que) {
    --que->tail;
}

DataType QueueGetFront(struct Queue* que) {
    return que->data[ que->head ];
}
DataType QueueGetRear(struct Queue* que) {
    return que->data[ que->tail - 1 ];
}
int QueueGetSize(struct Queue* que) {
    return que->tail - que->head;
}
int QueueIsEmpty(struct Queue* que) {
    return !QueueGetSize(que);
}

/**************************** 顺序表 实现队列 ****************************/


int longestSubarray(int* nums, int numsSize, int limit) {
    int i, len;
    int left = 0, retLen = 0;
    struct Queue *maxQ = (struct Queue *) malloc ( sizeof( struct Queue ));
    struct Queue *minQ = (struct Queue *) malloc ( sizeof( struct Queue ));
    QueueClear(maxQ), QueueClear(minQ);
    for(i = 0; i < numsSize; ++i) {
        while(!QueueIsEmpty(maxQ) && nums[ QueueGetRear(maxQ) ] < nums[i])    // (1) 
            QueueDequeueRear(maxQ);
        while(!QueueIsEmpty(minQ) && nums[ QueueGetRear(minQ) ] > nums[i])    // (2) 
            QueueDequeueRear(minQ);
        
        QueueEnqueue(maxQ, i);                                                // (3) 
        QueueEnqueue(minQ, i);                                                // (4) 

        while(!QueueIsEmpty(maxQ)) {                                          // (5) 
            if( nums[ QueueGetFront(maxQ) ] - nums[ QueueGetFront(minQ) ] > limit ) {
                left ++;
                while (QueueGetFront(maxQ) < left)
                    QueueDequeueFront(maxQ);
                while(QueueGetFront(minQ) < left)
                    QueueDequeueFront(minQ);
            }else {
                break;
            }
        }
        len = i - left + 1;                                                   // (6) 
        if(len > retLen) {
            retLen = len;
        }
    }
    return retLen;
}

  • ( 1 ) (1) (1) 构造单调递减队列;
  • ( 2 ) (2) (2) 构造单调递增队列;
  • ( 3 ) (3) (3) 当前元素必须插入单调递减队列;
  • ( 4 ) (4) (4) 当前元素必须插入单调递增队列;
  • ( 5 ) (5) (5) 如果不满足要求,则自增左区间,并且当队列元素小于左区间时,执行出队操作;
  • ( 6 ) (6) (6) 取一个合法长度,更新最终值;

三、本题小知识

   一般遇到求任意两个元素的绝对差问题,可以转换成求 最小值 和 最大值 问题。


以上是关于⭐算法入门⭐《队列 - 单调队列》中等02 —— LeetCode 1438. 绝对差不超过限制的最长连续子数组的主要内容,如果未能解决你的问题,请参考以下文章

⭐算法入门⭐《队列 - 单调队列》中等04 —— LeetCode 剑指 Offer 59 - II. 队列的最大值

⭐算法入门⭐《队列 - 单调队列》中等03 —— LeetCode 918. 环形子数组的最大和

⭐算法入门⭐《队列 - 单调队列》困难02 —— LeetCode1425. 带限制的子序列和

⭐算法入门⭐《队列 - 单调队列》困难01 —— LeetCode 239. 滑动窗口最大值

⭐算法入门⭐《队列 - 单调队列》困难03 —— LeetCode 862. 和至少为 K 的最短子数组

单调队列——从入门到入门