1. 程式人生 > >0.分治永遠大於順序?關於最大子序列和問題的思考

0.分治永遠大於順序?關於最大子序列和問題的思考

right -s 三層 代碼 不同的 復雜 round 開始 center

p17. 2.4.3 最大子序列和的問題的解

題目:給定整數A1,A2,......,AN,k=i~jAk的最大值(如果所有整數都為負數,則最大子序列和為0)

書中給出了四種不同的算法,時間復雜度依次降低,下面我簡單描述一下這四種算法

第一種:窮舉法

求出所有子序列和,比較得出最大的

最簡單想到的代碼,效率十分低下,原因是沒有利用數列的連貫性,對數列元素反復檢索造成浪費

三層嵌套循環,時間復雜度

T(N)=O(N3)

int 
Maxsubsum(const int A[],int N)
{
    int ThisSum,Maxsum,i,j,k;
    
    Maxsum=0
; for(i=0;i<N;i++)              //確定各個子序列的首項 for(j=i;j<N;j++)            //確定每個序列的元素個數 { ThisSum=0; for(k=i;k<=j;k++) /*開始按照確定的元素個數選出數列並計算子列和,較大者覆蓋Maxsum,較小者在ThisSum中被丟棄*/ ThisSum += A[k]; if(ThisSum>Maxsum) Maxsum
=ThisSum; } return Maxsum; }

第二種:改良後的窮舉法

顧名思義,這種方法對方法一進行了改良.

當第選定了子序列的首項後,無需對子序列長度進行再次分組,直接順序列出所有該首項下的子數列即可,減去了一次循環。

實際上換湯不換藥

時間復雜度依舊為冪函數級

T(N)=O(N2)

int 
Maxsubsum(const int A[],int N)
{
    int ThisSum,Maxsum,i,j,k;
    
    Maxsum=0;                     
    for(i=0;i<N;i++)//確定各個子序列的首項
{ ThisSum=0; for(k=i;k<=j;k++)/*開始按照確定的元素個數選出數列並計算子列和,較大者覆蓋Maxsum,較小者在ThisSum中被丟棄*/ { ThisSum += A[k]; if(ThisSum>Maxsum) Maxsum=ThisSum; } } return Maxsum; }

第三種:分治法


這是我們今天著重要探討的第一種算法。

先上代碼。

 1 #include "stdio.h"
 2 int
 3 MaxSubSum(const int A[],int left,int right)//left,right分別為數列數組第一個元素和最後一個元素的下標
 4 {
 5     int Maxleftsum,Maxrightsum;
 6     int Maxleftbordersum,Maxrightbordersum;
 7     int leftbordersum,rightbordersum;
 8     int Center,i;
 9 
10     if(left==right)    /*base case*/
11         if(A[left]>0)
12             return A[left];
13         else
14             return 0;
15 
16 
17     Center=(left+right)/2;
18     Maxleftsum=MaxSubSum(A,left,Center);
19     Maxrightsum=MaxSubSum(A,Center+1,right);
20 
21     Maxleftbordersum=0;leftbordersum=0;
22     for(i=Center;i>=left;i--)
23     {
24         leftbordersum +=A[i]
25         if(leftbordersum>Maxleftbordersum)
26             Maxleftbordersum=leftbordersum;
27     }
28 
29     Maxrightbordersum=0;rightbordersum=0;
30     for(i=Center+1;i<=right;i++)
31     {
32         rightbordersum +=A[i]
33         if(rightbordersum>Maxrightbordersum)
34             Maxrightbordersum=rightbordersum;
35     }
36 
37     return Max(Maxleftbordersum,Maxrightbordersum,Maxrightbordersum+Maxleftbordersum)
38 
39 }

看起來可能有些復雜哈,我第一次看也是半天看不懂,沒有這方面的基礎。

我們先來看一個簡單的問題來理解啥叫分治。

0.分治永遠大於順序?關於最大子序列和問題的思考