⭐算法入门⭐《队列 - 单调队列》困难03 —— LeetCode 862. 和至少为 K 的最短子数组
文章目录
- 一、题目
- 1、题目描述
- 2、基础框架
- 3、原题链接
- 二、解题报告
- 1、思路分析
- 2、时间复杂度
- 3、代码详解
- 三、本题小知识
- 四、加群须知
一、题目
1、题目描述
返回数组 AAA 的最短的非空连续子数组的长度,该子数组的和至少为 KKK。如果没有和至少为 KKK 的非空子数组,返回 −1-1−1。
样例输入:A = [1,4,-5,6,5,-7,-3,11,-5,-1,-1,8,-6,5,-4,3], K = 13
样例输出:9
2、基础框架
- C语言 版本给出的基础框架代码如下:
int shortestSubarray(int* nums, int numsSize, int k){}
3、原题链接
LeetCode 862. 和至少为 K 的最短子数组
二、解题报告
1、思路分析
1)令 sum[i]sum[i]sum[i] 代表 A[i]A[i]A[i] 的前缀和,对于一段左开右闭子数组 (t,i](t, i](t,i], sum[i]−sum[t]sum[i] - sum[t]sum[i]−sum[t] 就是这段子数组的和,其中 −1≤t<i-1 \le t < i−1≤t<i,并且必须满足数组和 sum[i]−sum[t]≥Ksum[i] - sum[t] \ge Ksum[i]−sum[t]≥K。
2)对于两个下标 t1<t2t_1 \lt t_2t1<t2, 如果 sum[t1]≥sum[t2]sum[t_1] \ge sum[t_2]sum[t1]≥sum[t2],则 sum[t1]sum[t_1]sum[t1] 不会比 sum[t2]sum[t_2]sum[t2] 更优,所以,我们只需要维护一个 sumsumsum 值单调递增的单调队列;
3)单调队列的队首一定是 sumsumsum 值最小的,sum[i]−sum[queuefront]≥Ksum[i] - sum[queuefront] \ge Ksum[i]−sum[queuefront]≥K,则记录 i−queuefronti - queuefronti−queuefront 作为一个候选解,并且弹出队首;
4)然后只需要枚举 iii,维护 sum[i]sum[i]sum[i] 的单调队列,且单调队列插入的是前缀和的下标值,候选最优值 i−queuefronti - queuefronti−queuefront 用于和最终最优值进行比较取小者;
2、时间复杂度
单调队列进出是 O(n)O(n)O(n),枚举下标的过程和单调队列的进出无关,也是 O(n)O(n)O(n)。所以,总的时间复杂度为 O(n)O(n)O(n)。
3、代码详解
/**************************** 顺序表 实现双端队列 ****************************/
#define DataType int
#define maxn 100005struct 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);
}/**************************** 顺序表 实现双端队列 ****************************/struct Queue q;
int sum[maxn];int getValue(int index) {if(index == -1) {return 0;}return sum[index];
}int shortestSubarray(int* nums, int numsSize, int k){int i;int len, minlen;for(i = 0; i < numsSize; ++i) {sum[i] = nums[i];if(i)sum[i] += sum[i-1];}QueueClear(&q);QueueEnqueue(&q, -1); // (1)minlen = numsSize + 1;for(i = 0; i < numsSize; ++i) {while(!QueueIsEmpty(&q) && getValue( QueueGetRear(&q) ) >= getValue(i))QueueDequeueRear(&q); // (2)while(!QueueIsEmpty(&q) && getValue(i) - getValue( QueueGetFront(&q) ) >= k) {len = i - QueueGetFront(&q);if (len < minlen) {minlen = len; // (3)}QueueDequeueFront(&q);}QueueEnqueue(&q, i);}return minlen == numsSize + 1 ? -1 : minlen;
}
- (1)(1)(1) 相当于插入一个 sum[−1]sum[-1]sum[−1];
- (2)(2)(2) 保证一个单调递增的队列;
- (3)(3)(3) 找到一个可行解;
三、本题小知识
单调队列的问题一般都是配合前缀和来求解。
四、加群须知
相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」。
那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:
寻找和至少为K的最短子数组 1. 题目 题目来自LeetCode: https://leetcode-cn.com/problems/shortest-subarray-with-sum-at-lea ... 0862_和至少为 K 的最短子数组 题目描述 返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K . 如果没有和至少为 K 的非空子数组,返回 -1 . 示例1: 输入:A = [1], ... 1. 题目 返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K . 如果没有和至少为 K 的非空子数组,返回 -1 . 示例 1: 输入:A = [1], K = 1 输出:1示例 2: ... 插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到网站. 坚持不懈,越努力越幸运,大家一起学习鸭~~~ 3妹:小呀么小二郎呀, 背着那书包上学堂. 2 ... 这几天力扣总算是放我这个菜鸡一马,来了一些中等难度题.和可被K整除的子数组,一看到反正最近脑子里都是双指针.滑动窗.前缀和.动态规划之类的东西.话不多说,赶紧看一看今天的题. 974.和可被K整除的子 ... 文章目录 一.题目 1.题目描述 2.基础框架 3.原题链接 二.解题报告 1.思路分析 1)初始化前缀和 2)哈希表统计 2.时间复杂度 3.代码详解 三.本题小知识 四.加群须知 一.题目 1.题 ... 文章目录 一.题目 1.题目描述 2.基础框架 3.原题链接 二.解题报告 1.思路分析 2.时间复杂度 3.代码详解 三.本题小知识 四.加群须知 一.题目 1.题目描述 给定两个以升序排列的整 ... [题目]*974. 和可被 K 整除的子数组 给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续.非空)子数组的数目. 示例: 输入:A = [4,5,0,-2,-3,1], K = 5 输 ... 给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续.非空)子数组的数目. 示例: 输入:A = [4,5,0,-2,-3,1], K = 5 输出:7 解释: 有 7 个子数组满足其元素之和 ...⭐算法入门⭐《队列 - 单调队列》困难03 —— LeetCode 862. 和至少为 K 的最短子数组相关推荐
最新文章
热门文章