Leetcode第862题:和至少为K的最短子数组(Shortest Subarray with sum at least k)
解题思路
前缀和
定义前缀和, 。
例如 ,对应的前缀和数组为。
通过前缀和,可以将子数组和转换为两个前缀和的差,即
例如的子数组的和就可以用计算出来.
此时就可以通过枚举所有且的子数组,取其中最小的作为答案.
单调队列
枚举所有前缀和子数组的时间复杂度是,使用某个数据结构维护遍历过的,及时移除无用的.
第一,当遍历到时,如果左边存在某个,满足,那么无论右边的数字大小,都不会把当作子数组的左端点,然后得到一个比更短的子数组.因此可以将移除.
第二,如果,假如后续有数字能和组成满足要求的子数组,即,那么必然也有,由于从到的子数组更短,因此可以将移除.
做完这两个优化后,再把加到这个数据结构中.第二个优化保证了数据结构中的会形成一个递增的序列,因此第一个优化移除的是序列最左侧的若干元素,第二个优化移除的是最右侧的若干元素.因此该数据结构满足移除最左端元素和最右端元素,以及在最右端添加元素,故选用双端队列.元素保持单调递增的双端队列也成为单调队列.
核心代码如下:
int shortestSubarray(vector<int> &nums, int k) { int n = nums.size(), ans = n + 1; long s[n + 1]; s[0] = 0L; for (int i = 0; i < n; ++i) s[i + 1] = s[i] + nums[i]; // 计算前缀和 deque<int> q; for (int i = 0; i <= n; ++i) { long cur_s = s[i]; while (!q.empty() && cur_s - s[q.front()] >= k) { ans = min(ans, i - q.front()); q.pop_front(); // 优化一 } while (!q.empty() && s[q.back()] >= cur_s) q.pop_back(); // 优化二 q.push_back(i); } return ans > n ? -1 : ans; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下