返回 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
方法一:优先队列。(自己的方法)
我们使用优先队列存储前缀和以及对应的索引,并按照升序排序,用遍历到当前位置的前缀和与队列的首元素进行比较,若差值大于等于K,则说明这一段子数组是符合要求的,我们更新答案后弹出首元素并继续比较,若小于K,则说明当前位置之前剩下所能构成的连续子数组的和不会大于等于K,因此加入当前值并继续往下遍历。
class Solution {
class node implements Comparable<node>{
long val;
int index;
public node(long val,int index) {
this.val=val;
this.index=index;
}
@Override
public int compareTo(node o) {
// TODO 自动生成的方法存根
if(val==o.val)
return o.index-index;
return val<o.val?-1:1;
}
}
public int shortestSubarray(int[] A, int K) {
int n=A.length;
long[] sum=new long[n];
PriorityQueue<node> q=new PriorityQueue<>();
int ans=n+1;
sum[0]=A[0];
q.add(new node(sum[0],0));
if(sum[0]>=K) return 1;
for(int i=1;i<n;i++) {
sum[i]=sum[i-1]+A[i];
while(!q.isEmpty() && sum[i]-q.peek().val>=K)
ans=Math.min(ans, i-q.poll().index);
if(sum[i]>=K) ans=Math.min(ans, i+1);
q.add(new node(sum[i],i));
}
return ans>n?-1:ans;
}
}
方法二:滑动窗口。(参考官方题解)
首先我们预处理出前缀和sun数组,而我们的目标是找到x和y使得sum[y]-sum[x]>=K并且y-x尽可能的小,我们令f(y)表示对于固定的y,最大的满足sum[x]<=sum[y]-K的x,这样所有y-f(y)中的最小值即为答案,我们可以从中发现两条性质:
(1)假设两个索引x1和x2,其中x1<x2,满足sum[x2]<=sum[x1],那么f(y)的值一定不会为x1,因为x2比x1大,并且如果x1满足了sum[x1]<=f(y)-K。那么sum[x2]<=sum[x1]<=sum[y]-K,即x2同样满足sum[x2]<=sum[y]-K。
(2)若f(y1)的值为x,那么之后就没必要再考虑x了,因为如果有y2>y1且f(y2)的值也为x,但此时y2-x显然大于y1-x,不会作为所有y-f(y)中的最小值。
我们维护一个前缀和数组sum的单调队列,它是一个双端队列,其中存放的元素为下标x0,x1,x2...满足sum[x0],sum[x1]...单调递增,我们可以通过在队尾移除若干元素使得队列单调递增。这是为了满足性质(1)。
同时,我们也会在队首移除若干元素,如果sum[y]>=sum[x0]+K,则将队首元素移除,直到该不等式不满足,这是为了满足性质(2)。
class Solution {
public int shortestSubarray(int[] A, int K) {
int n=A.length;
long[] sum=new long[n+1];
Deque<Integer> q=new LinkedList<>();
int ans=n+1;
for(int i=0;i<n;i++)
sum[i+1]=sum[i]+A[i];
for(int i=0;i<sum.length;i++) {
while(!q.isEmpty() && sum[i]<=sum[q.getLast()])
q.removeLast();
while(!q.isEmpty() && sum[i]>=sum[q.getFirst()]+K)
ans=Math.min(ans, i-q.removeFirst());
q.addLast(i);
}
return ans>n?-1:ans;
}
}