题目:
给你一个整数数组 nums
和一个整数 k
,找出 nums
中和至少为 k
的 最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1
。
子数组 是数组中 连续 的一部分。
示例 1:
输入:nums = [1], k = 1 输出:1
示例 2:
输入:nums = [1,2], k = 4 输出:-1
示例 3:
输入:nums = [2,-1,2], k = 3 输出:3
提示:
1 <= nums.length <= 105
-105 <= nums[i] <= 105
1 <= k <= 109
思路:
求子数组的和可以用前缀和。
求最小长度可以又双指针做(我第一次这样超时了),然后想到用单调队列来维护,保证队列中前缀和严格递增。
为什么是递增,举个例子,假设前缀和为 1 3 2 4 那么为3的这个前缀和就用不到啦,4-2比4-3要大,但长度又小,所以我们可以用单调队列维护。
class Solution {
public int shortestSubarray(int[] nums, int k) {
int n=nums.length;
long[] sum = new long[n+10];
sum[0]=0;
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+nums[i-1];
}
int ans = n+1;
int[] qq = new int[ans];
int hh=0;
int tt=-1;
qq[++tt]=0;
for(int i=1;i<=n;i++){
while (tt>=hh&&sum[i]-sum[qq[hh]]>=k)ans=Math.min(ans,i-qq[hh++]);
while (tt>=hh&&sum[i]<sum[qq[tt]])tt--;
qq[++tt]=i;
}
if(ans>n) return -1;
else return ans;
}
}