小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
862. 和至少为 K 的最短子数组
返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。
如果没有和至少为 K 的非空子数组,返回 -1 。
- 示例 1:
输入:A = [1], K = 1 输出:1
- 示例 2:
输入:A = [1,2], K = 4 输出:-1
- 示例 3:
输入:A = [2,-1,2], K = 3 输出:3
提示:
- 1 <= A.length <= 50000
- -10 ^ 5 <= A[i] <= 10 ^ 5
- 1 <= K <= 10 ^ 9
解题思路
- 对于新加入的y,前面的P[x]都要比新加入的P[y]要小,比P[y]大的P[?]都要pop掉,甚至如果都比P[y]大,整个队列都要清空。为什么?
因为对于当前y来说,必须满足P[y]-P[x]>=K,k又必然是正数,所以p[y]必须大于p[x]。对于y后面的y2来说,即使满足P[y2]-P[x]>=K,[x,y2]之间也不是最短的,因为p[y]<p[x],所以必然满足P[y2]-P[y]>=K,y比x更加接近y2,生成的长度更短,所以x可以直接pop掉,对答案不会产生影响
- 为什么当队列里第一个x满足P[y]-P[x]>=K的时候,第一个x可以被pop掉?
因为此时我们构成了一个P[y]-P[x]>=K,这个y已经是最接近x的了,即长度最短,后面即使还能满足P[y]-P[x]>=K,长度也不够当前长度短
代码
class Solution {
public int shortestSubarray(int[] nums, int k) {
int n=nums.length,res=n+1;
LinkedList<Integer> list=new LinkedList<>();
long[] pre=new long[n+1];
for(int i=1;i<=n;i++)
pre[i]=pre[i-1]+(long)nums[i-1];
for(int i=0;i<n+1;i++)
{
while(!list.isEmpty()&&pre[i]<pre[list.getLast()])
list.removeLast();
while(!list.isEmpty()&&pre[i]-pre[list.getFirst()]>=k)
{
res=Math.min(res,i-list.removeFirst());
}
list.add(i);
}
return res==n+1?-1:res;
}
}