和至少爲 K 的最短子數組

//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;
	}
發佈了124 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章