//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;
}