求最大欄位和問題(常規法,分治法,動態規劃法)
阿新 • • 發佈:2019-01-30
演算法設計與分析-----求最大欄位和問題
問題描述:給定由n個整陣列成的序列(a1,a2,a3......,an),求該序列的子段的最大值.
-
常規法:
從a1開始,求出以a1開頭的子序列最大的和為sum,依次從a2開始,在sum等於以a1開頭的基礎上,與以a2開頭的不同長度的子序列進行比較,取最大值,然後依次從a3,a4......an開頭,最後得到最大子序列的和;
int maxSum(int a[],int n) { int ThisSum,MaxSum=0,i,j,k; for(i=0;i<n;i++){ ThisSum=0; for(j=i;j<n;j++){ ThisSum+=a[j]; if(ThisSum>MaxSum){ MaxSum=ThisSum; //每一趟的最大值 } } } return MaxSum; }
-
分治法:
用分治法求最大欄位和首先將問題劃分,即將一個整序列劃分成長度相等的兩個序列,這時會出現3種情況,即1,最大欄位和在第一個序列, 2最大欄位和在第二序列,3,最大欄位和在第一個序列和第二個序列之間.然後將這3中情況的最大欄位合併,取3者之中的最大值為問題的解.
int Max3(int a,int b,int c) //求三種情況下的最大值; { int max =a; if(max < b) max=b; if(max < c) max=c; return max; } int MaxSubSum(int *a,int fI,int lI) { int i=0; int mI=(fI+lI)>>2; //右移相當於除於2,左移相當於乘於2; int lMax=0,rMax=0,lMaxBorder=0,rMaxBorder=0,lSumBorder=0,rSumBorder=0,max=0; if(fI==lI){ return *(a+fI); } lMax=MaxSubSum(a,fI,mI); //對應情況1,遞迴求解 rMax=MaxSubSum(a,mI+1,lI); //對應情況2,遞迴求解 for(i=mI;i>=fI;i--){ //求左邊界的最大欄位和; lSumBorder+=*(a+i); if(lMaxBorder < lSumBorder){ lMaxBorder=lSumBorder; //包括左邊界的最大值放在lMaxBorder } } for(i=mI+1;i<=lI;i++){ //求右邊界的最大欄位和; rSumBorder+=*(a+i); if(rMaxBorder < rSumBorder){ rMaxBorder=rSumBorder; } } max=Max3(lMax,rMax,lMaxBorder+rMaxBorder); return max; }
- 動態規劃法
設All[i]為子問題A[i...n-1]的連續子序列之和的最大值,start[i]為從A[i]開始的連續之和的最大值,因此:
All[i]=A[n-1] ,當i=n-1時;
All[i]=max{All[i+1],start[i]} i=0,1,2....n-2;
其中start[i]為:
start[i]=A[n-1],當i=n-1時;
start[i]=max{A[i],A[i]+start[i+1]} i=0,1,2,3.....n-2;
程式碼如下:
int max(int a, int b) { return a > b ? a:b; } int maxSum(int A[], int n) { int All[n], start[n], i; start[n - 1] = All[n - 1] = A[n - 1]; for (i = n - 2;i >= 0;i--) { start[i] = max(A[i], A[i] + start[i + 1]); All[i] = max(All[i + 1], start[i]); } return All[0]; }
下面是對空間複雜度的優化:
int max(int a, int b) { return a > b ? a:b; } int maxSum(int A[], int n) { int start, All, i; start = All = A[n - 1]; for (i = n - 2;i >= 0;i--) { start = max(A[i], A[i] + start); All = max(All, start); } return All; }
時間複雜度為 O(n);