0.分治永遠大於順序?關於最大子序列和問題的思考
阿新 • • 發佈:2018-10-22
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.分治永遠大於順序?關於最大子序列和問題的思考