1. 程式人生 > >求最大欄位和問題(常規法,分治法,動態規劃法)

求最大欄位和問題(常規法,分治法,動態規劃法)

演算法設計與分析-----求最大欄位和問題   

問題描述:給定由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);