演算法學習-零子陣列,最大連續子陣列
阿新 • • 發佈:2019-02-20
題目
演算法流程對於長度為N的陣列A,求連續子陣列的和最接近0的值。
如:
陣列A:1,-2,3,10,-4,7,2,-5
它是所有子陣列中,和最接近0的是哪個?
申請比A長1的空間sum[-1,0,...,N-1],sum[i]是A的前i項和。定義sum[-1]=0
顯然有:A的i到j項和=sum(j)-sum(i-1)
演算法思路:
對sum[-1,0,...,N-1]排序,然後計算sum相鄰元素的差的絕對值,最小即為所求
在A中任意取兩個字首子陣列的和,求差的最小值。
討論
計算前n項和陣列sum和計算sum相鄰元素差的時間複雜度,都是O(N),排序的時間複雜度認為是O(N*logN),因此,總時間複雜度:O(NlogN)。
思考:如果需要返回絕對值最小的子陣列本身呢?
程式碼如下
int MinSubarray(const int* a, int size) { int* sum = new int[size + 1]; sum[0] = 0; int i; for (i = 0; i < size; i++) { sum[i + 1] = sum[i] + a[i]; } sort(sum, sum + size + 1); int difference = abs(sum[1] - sum[0]); int result = difference; for (i = 1; i < size; i++) { difference = abs(sum[i + 1] - sum[i]); result = min(difference, result); } delete[] sum; return result; }
下面來看一下最大連續子陣列的問題
給定一個數組A[0,...,n-1],求A的連續子陣列,使得該子陣列的和最大。
例如:陣列1,-2,3,10,-4,7,2,-5最大子陣列:3,10,-4,7,2
分析
程式碼如下記S[i]為以A[i]結尾的陣列中和最大的子陣列,則:S[i+1]=max(S[i]+A[i+1],A[i+1])
S[0]=A[0]
遍歷i:0<=i<=n-1
動態規劃:最優子問題
時間複雜度O(n)
int MaxSubarray(const int* a, int size) { if (!a || (size <= 0)) return 0; int sum = a[0]; // 當前子串的和 int result = sum; // 當前找到的最優解 for (int i = 1; i < size; i++) { if (sum > 0) { sum += a[i]; } else { sum = a[i]; } result = max(sum, result); } return result; }
求最大子陣列還有一種思路如下:
定義:字首和sum[i]=a[0]+a[1]+...+a[i]則:a[i,j]=sum[j]-sum[i-1](定義p[-1]=0),最大子陣列=sum(j)-sum(i-1)
演算法過程
- 求i字首sum[i]:
- 遍歷i:0<=i<=n-1
- sum[i]=sum[i-1]+a[i]
- 計算以a[j]結尾的子陣列的最大值
- 對於某個j:遍歷0<=i<=j,求sum[i]的最小值m
- sum[j]-m即為a[j]結尾的陣列中最大的子陣列的值
- 統計sum[j]-m的最大值,0<=j<=n-1
- 1,2,3步都是線性的,因此,時間複雜度O(n)。
如果要求子陣列本身,只需要記錄一下from和to就可以了