解题思路:
从求和再加上数组的长度,很容易联想到以空间换时间的方法——前缀和,由于数组中元素有负数,所以无法通过前缀和的单调性直接判断出结果,所以我们定义一个队列,用来存储已经访问过的前缀和下标,这些下标表示以该下标开始的序列目前还没找到满足条件的子序列,遍历每个前缀和,和队首进行比较,把所有满足条件的前缀和长度进行更新,并把队首出队列(已经找到满足条件的最短序列就不用留在队列中),同时对于留在队列中的前缀和下标,从队尾开始比较是否比当前前缀和大,大了也直接出队列,这相当于剪枝,因为保证序列最短,最后将当前前缀和放入队列中,代码如下:
class Solution {
public:
int shortestSubarray(vector<int>& nums, int k) {
int n = nums.size();
vector<long> prefix(n + 1, 0);
for(int i = 1; i <= n; i ++) {
prefix[i] = prefix[i - 1] + nums[i - 1];
}
int minLen = INT_MAX;
deque<int> q;
for(int i = 0; i <= n; i ++) {
long curSum = prefix[i];
// 如果当前位置到队首的和满足k的条件
while(!q.empty() && curSum - prefix[q.front()] >= k) {
minLen = min(minLen, i - q.front());
q.pop_front();
}
// 把队尾大的前缀和去掉
while(!q.empty() && curSum <= prefix[q.back()]) {
q.pop_back();
}
q.push_back(i);
}
return minLen == INT_MAX ? -1 : minLen;
}
};