Link
https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/
Description
Problem Statement
Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K.If there is no non-empty subarray with sum at least K, return -1.
Sample Input
Input: A = [1], K = 1
Sample Output
Output: 1
Sample Input
Input: A = [2,-1,2], K = 3
Sample Output
Output: 3
Solution
题目即让我们求区间和大于 k k k的最小长度的子区间。我们预处理一下前缀和,如果给定序列中不出现负数,即前缀和递增,我们是可以使用双指针进行滑窗的(即尺取法)。
但是这题序列中会出现负数,前缀和非单调,那么考虑使用单调队列
deque中维护一个从尾到头递减的前缀和的下标。关键在于deque的实现,叙述起来较麻烦,建议模拟一下。细节见注释
通常单调队列中就是维护一个具有单调性,并且满足一定条件的序列。
Code
class Solution {
public:
int shortestSubarray(vector<int>& A, int K) {
int cnt=A.size();
if(cnt==0)return -1;
int sum[1000065];
for(int i=0;i<cnt;i++)
sum[i+1]=sum[i]+a[i];
int minn=0x3f3f3f;
deque<int>q;
q.push_back(0);
for(int i=1;i<=cnt;i++){
while(q.size()&&sum[i]-sum[q.front()]>=k){//对于sum[i]-sum[q.front()]
minn=(minn,i-q,front());//sum[i]是固定的,sum[q.front()]在队列中
q.pop_front();//从头到尾是递增的(因为是q.front()),整个的和就是递减的
//那么可能存在某一个sum[q.front()]使区间和小于k,而在之前的
//区间和都是大于等于k的,从而在之前是更新了minn的
}
while(q.size()&&sum[i]<sum[q.back()])//此循环为保证队列从尾到头
q.pop_back(); //是递减的,从头到尾递增的
q.push_back(i);
}
return minn==0x3f3f3f?-1:minn;
}
};
我们坚持一件事情,并不是因为这样做了会有效果,而是坚信,这样做是对的。
——哈维尔