//https://github.com/Shellbye/Shellbye.github.io/issues/41
问题描述
返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。
如果没有和至少为 K 的非空子数组,返回 -1 。(LeetCode862 困难)
样例
输入:A = [2,-1,2], K = 3
输出:3
题解
暴力法:
- 求出每个子数组的和(以i作为起始点,j为终止点)和目标元素对比。
- 时间复杂度O(n3)
private int ways1(int[] a, int aim) {
//暴力解法
if(a==null||a.length==0)
return -1;
int len=a.length+1;
for(int i=0;i<a.length;i++) {
for(int j=i;j<a.length;j++) {
int sum=0;
for(int k=i;k<=j;k++) {
sum+=a[k];
}
if(sum>=aim) {
len=Math.min(len, j-i+1);
}
}
}
return len==a.length+1?-1:len;
}
改进方法1
- 前j+1个元素的和就是前j个元素的和再加第j+1个元素。即pre[j+1]=pre[j]+a[j+1]
- 第i个元素到第j个元素的和就等于pre[j]-pre[i]
- 时间复杂度O(n2)
private int ways2(int[] a, int aim) {
// TODO Auto-generated method stub
int len=a.length+1;
int []pre=new int[a.length+1];
pre[0]=0;
for(int i=1;i<=a.length;i++) {
pre[i]=a[i]+pre[i-1];
}
for(int i=0;i<a.length;i++) {
for(int j=i+1;j<a.length+1;j++) {
if(pre[j]-pre[i]>=aim)
len=Math.min(len, j-i);
}
}
return len==a.length+1?-1:len;
}
改进方法2
- 当pre[x2]<=pre[x1]时,pre[xn]-pre[x2]>=pre[xn]-pre[x1],那么x1下标可以移除了。因为x1下标满足的x2下标也满足
- 如果pre[x2]-pre[x1]已经大于等于k,那么x1就可以不用再考虑了,因为没有比x2距离x1最近的了。
private int ways3(int[] A, int K) {
// TODO Auto-generated method stub
int len=A.length+1;
int[]pre=new int[A.length+1];
pre[0]=0;
for(int i=0;i<A.length;i++) {
pre[i+1]=pre[i]+A[i];
}
LinkedList<Integer> list=new LinkedList<>();
for(int i=0;i<A.length+1;i++) {
while(!list.isEmpty()&&pre[i]<=pre[list.peekLast()])
list.pollLast();
while(!list.isEmpty()&&pre[i]-pre[list.peekFirst()]>=K) {
int newLen=i-list.pollFirst();
len=Math.min(len, newLen);
}
list.add(i);
}
return len==A.length+1?-1:len;
}