题目:
给你一个整数数组 nums 和一个整数 k ,找出 nums 中和至少为 k 的 最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1 。
子数组 是数组中 连续 的一部分。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k
解题思路:
通过前缀和,我们可以把子数组的和转换成两个前缀和的差,求出nums 的前缀和 s 后,我们可以写一个暴力算法,枚举所有满足 i>j且s[i]−s[j]≥k 的子数组 [j,i),取其中最小的 i-j 作为答案。但是需要优化,不然会超时。这里采用双端队列进行优化。
C++:
class Solution {
public:
int shortestSubarray(vector<int>& nums, int k) {
int n = nums.size();
long ans = n + 1;
vector<long> s; //前缀数组
s.resize(n+1);
s[0] = 0L;
for (int i = 0;i < n;i++) { //初试化前缀数组
s[i+1] = s[i] + nums[i];
}
deque<long> q; //双端队列记录
for (int i = 0;i <=n;i++) {
long cur_s = s[i];
while (!q.empty() && cur_s - s[q.front()] >= k) {//满足题目条件时,将q.front退队,记录长度
ans = min(ans, i - q.front());
q.pop_front();
}
while (!q.empty() && cur_s <= s[q.back()])//当后面的数小于前面的数时,将队中所有大于当前数的全部退队
q.pop_back();
q.push_back(i);
}
return ans > n ? -1 : ans;//ans长度大于原数组长度时,说明没有符合题意的情况
}
};