⭐算法入门⭐《队列 - 单调队列》中等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}
ai≤ai+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. 滑动窗口最大值