文章目录
题目
代码(7.17 首刷看解析)
这是这几天以来做过最难的题了,这个题和Leetcode 209. 长度最小的子数组不一样,因为这个题有负数,如果用滑动窗口,一直加,就不会有答案。
用到了前缀和+单调队列
- 使用前缀和的差来计算子数组的和;
- 使用一种数据结构,将当前前缀和i与最前面的前缀和j作差,如果满足>=k的条件,那么j在之后就可以不用看了。【因为即使后面也有满足条件的,长度也会更长,所以需要将j从前面弹出】;
- 第2步完成了之后,当前的i也要放入数据结构,那么如果数据结构中有前缀和j比前缀和i大,j也可以不用看了。【因为即使后面有满足条件的,与i作差肯定也满足条件,并且长度更短,所以需要将大于等于i的从后面弹出】。
class Solution {
public:
int shortestSubarray(vector<int>& nums, int k) {
int n = nums.size();
vector<long> preSumArr(n+1);
for(int i = 0; i < n; i++) {
preSumArr[i + 1] = preSumArr[i] + nums[i];
}
int res = n + 1;
deque<int> q;
for(int i = 0; i <= n; i++) {
long curSum = preSumArr[i];
while(!q.empty() && curSum - preSumArr[q.front()] >= k) {
res = min(res, i - q.front());
q.pop_front(); // 后续即使还有以它为起点的满足条件的子数组,长度也会大于当前的长度
}
while(!q.empty() && preSumArr[q.back()] >= curSum)
q.pop_back(); // 作为减数时,更大的值只会让不等式更难满足;即使都满足,后访问到的值也可以带来更短的长度
q.push_back(i);
}
return res == n+1 ? -1 : res;
}
};