第四篇–演算法導論-最大子數組問題

來源:互聯網
上載者:User

  第四章:分治策略。分治策略原理已經在歸併排序中闡述,此處不再重複。

  最大子數組問題:

  問題:給定一個數組A[1..n],尋找A的和最大的非空連續子數組。

例如這個數組,的最大子數組就是A[8..11]

 首先是暴力求解方法:

 找出所有組合:總共theta(n^2)個組合,而處理每個組合,至少也是常量時間,所以已耗用時間為omega(n^2);注意這裡有重疊子問題,使用dynamic programming的思想可以簡化運算,此處不詳細闡述這類思想。

分治法是否可行?如果縮短序列長度,必然能帶來運算時間的下降,最重要的是分解之後,能否產生子問題的解?

將序列分解為A[low...mid]和A[mid+1...high]後,最大子數組A[i..j],必然在下列三種情況之中:

  1. 完全位於子數組A[low..mid]之中,因此low<=i<=j<=mid
  2. 完全位於子數組A[mid+1..high]之中,因此mid<i<=j<=high
  3. 橫跨了中點,因此low<=i<=mid<j<=high

這三種情況涵蓋了所有的情況,所以我們如果解決了merge時,第三種情況,就說明這個問題可以使用分治法。

//尋找第三種情況,只需找出形如A[i..mid]和A[mid+1..j]的最大子數組,再合并MERGE(A,low,mid,high)  left-sum=-INF  sum=0  for i=mid downto low     sum=sum+A[i] if sum>left-sum    left-sum=summax-left=i  right-sum=-INF  sum=0  for j=mid+1 to high      sum=sum+A[j]  if sum>right-sum     right-sum=sum max-right=j  return (max-left,max-right,left-sum+right-sum)  MERGE-FIND-MAXSUBARRAY(A,low,high)   if high==low      return (low,high,A[low])  //base case   else mid=floor( (low+high)/2)      (left-low,left-high,left-sum)=              MEGER-FIND-MAXSUBARRAY(A,low,mid)  (right-low,right-high,right-sum)=              MEGER-FIND-MAXSUBARRAY(A,low,mid)  (cross-low,cross-high,cross-sum)=              MERGE(A,low,mid,high)   if left-sum>=right-sum and left-sum>=cross-sum      return (left-low,left-high,left-sum)   else if right-sum>=left-sum and right-sum>=cross-sum      return (right-low,right-high,right-sum)   else      return (cross-low,cross-high,cross-sum)

時間複雜度分析:

merge程式的複雜度為theta(n)

對於merge_find:

T(n)=theta(1)          n=1

      =2T(n/2)+theta(n)   n>1

得出:T(n)=theta(nlgn)

c++代碼:

const int INF=INT_MAX;/*此段程式用於尋找最大子數組,由於模板編程運用的不是很熟練,所以這裡就沒有使用模板,預設 *數組輸入都是int型; *///結構體,用於記錄一個子數組的最大值,和取值區間struct MaxSubArray{int low;int high;int sum;};//合并程式,用於尋找第三種情況void merge(int* A,int low,int mid,int high,MaxSubArray* sub){int sum=0;//尋找A[low..mid]中的最大子數組部分A[i..mid]int left_sum=-INF;int max_left=0;for(int i=mid;i>=low;--i){sum+=A[i];if(sum>left_sum){left_sum=sum;max_left=i;}}sum=0;//尋找A[mid+1..high]中的最大子數組部分A[mid+1,j]int right_sum=-INF;int max_right=0;for(int j=mid+1;j<=high;++j){sum+=A[j];if(sum>right_sum){right_sum=sum;max_right=j;}}//給子數組對象賦值,表明這個最大子數組的區間 和 和值sub->low=max_left;sub->high=max_right;sub->sum=left_sum+right_sum;}void  merge_find(int* A,int low,int high,MaxSubArray* sub){if(high==low){//給總的最大子數組賦值sub->low=low;sub->high=high;sub->sum=A[low];}else{int mid=(low+high)/2;MaxSubArray left_sub;//找出左子數組A[low..mid]的最大子數組:left_submerge_find(A,low,mid,&left_sub);MaxSubArray right_sub;//找出右子數組A[mid+1..high]的最大子數組:right_submerge_find(A,mid+1,high,&right_sub);MaxSubArray cross_sub;//找出橫跨最大子數組:cross_submerge(A,low,mid,high,&cross_sub);//給總的最大子數組賦值if((left_sub.sum>=right_sub.sum)&&(left_sub.sum>=cross_sub.sum)){*sub=left_sub;}else if(right_sub.sum>=left_sub.sum && right_sub.sum>=cross_sub.sum){*sub=right_sub;}else{*sub=cross_sub;}}}

測試案例:

int main(){MaxSubArray total_sub;int A[16]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};merge_find(A,0,15,&total_sub);std::cout<<total_sub.low<<" "<<total_sub.high<<" "<<total_sub.sum;char c=getchar();}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.