程式員編程藝術:第七章、求連續子數組的最大和

來源:互聯網
上載者:User

 程式員編程藝術:第七章、求連續子數組的最大和 

作者:July。
出處:http://blog.csdn.net/v_JULY_v 。

前奏

  • 希望更多的人能和我一樣,把本狂想曲系列中的任何一道面試題當做一道簡單的編程題或一個實質性的問題來看待,在閱讀本狂想曲系列的過程中,希望你能盡量暫時放下所有有關面試的一切包袱,潛心攻克每一道“編程題”,在解決編程題的過程中,好好享受編程帶來的無限樂趣,與思考帶來的無限激情。--By @July_____。
  • 原狂想曲系列已更名為:程式員編程藝術系列。原狂想曲創作組更名為編程藝術室。編程藝術室致力於以下三點工作:1、針對一個問題,不斷尋找更高效的演算法,並予以編程實現。2、解決實際中會碰到的應用問題,如第十章、如何給10^7個資料量的磁碟檔案排序。3、經典演算法的研究與實現。總體突出一點:編程,如何高效的編程解決實際問題。歡迎有志者加入。

第一節、求子數組的最大和
3.求子數組的最大和
題目描述:
輸入一個整形數組,數組裡有正數也有負數。
數組中連續的一個或多個整數組成一個子數組,每個子數組都有一個和。
求所有子數組的和的最大值。要求時間複雜度為O(n)。

例如輸入的數組為1, -2, 3, 10, -4, 7, 2, -5,和最大的子數組為3, 10, -4, 7, 2,
因此輸出為該子數組的和18。

分析:這個問題在各大公司面試中出現頻率之頻繁,被人引用次數之多,非一般面試題可與之匹敵。單憑這點,就沒有理由不入選狂想曲系列中了。此題曾作為本人之前整理的微軟100題中的第3題,至今反響也很大。ok,下面,咱們來一步一步分析這個題:
      1、求一個數組的最大子數組和,如此序列1, -2, 3, 10, -4, 7, 2, -5,我想最最直觀也是最野蠻的辦法便是,三個for迴圈三層遍曆,求出數組中每一個子數組的和,最終求出這些子數組的最大的一個值。
記Sum[i, …, j]為數組A中第i個元素到第j個元素的和(其中0 <= i <= j < n),遍曆所有可能的Sum[i, …, j],那麼時間複雜度為O(N^3):

//本段代碼引自編程之美
int MaxSum(int* A, int n)
{
 int maximum = -INF;
 int sum=0;   
 for(int i = 0; i < n; i++)
 {
  for(int j = i; j < n; j++)
  {
   for(int k = i; k <= j; k++)
   {
    sum += A[k];
   }
   if(sum > maximum)
    maximum = sum;

   sum=0;   //這裡要記得清零,否則的話sum最終存放的是所有子數組的和。也就是編程之美上所說的bug。多謝蒼狼。
  }
 }
 return maximum;
} 

      2、其實這個問題,在我之前上傳的微軟100題,答案V0.2版[第1-20題答案],便直接給出了以下O(N)的演算法://copyright@ July 2010/10/18<br />//updated,2011.05.25.<br />#include <iostream.h></p><p>int maxSum(int* a, int n)<br />{<br />int sum=0;<br />//其實要處理全是負數的情況,很簡單,如稍後下面第3點所見,直接把這句改成:"int sum=a[0]"即可<br />//也可以不改,當全是負數的情況,直接返回0,也不見得不行。<br />int b=0;</p><p>for(int i=0; i<n; i++)<br />{<br />if(b<0) //...<br />b=a[i];<br />else<br />b+=a[i];<br />if(sum<b)<br />sum=b;<br />}<br />return sum;<br />}</p><p>int main()<br />{<br /> int a[10]={1, -2, 3, 10, -4, 7, 2, -5};<br />//int a[]={-1,-2,-3,-4}; //測試全是負數的用例<br /> cout<<maxSum(a,8)<<endl;<br /> return 0;<br />}</p><p>/*-------------------------------------<br />解釋下:<br />例如輸入的數組為1, -2, 3, 10, -4, 7, 2, -5,<br />那麼最大的子數組為3, 10, -4, 7, 2,<br />因此輸出為該子數組的和18。</p><p>所有的東西都在以下倆行,<br />即:<br />b : 0 1 -1 3 13 9 16 18 13<br />sum: 0 1 1 3 13 13 16 18 18</p><p>其實演算法很簡單,當前面的幾個數,加起來後,b<0後,<br />把b重新賦值,置為下一個元素,b=a[i]。<br />當b>sum,則更新sum=b;<br />若b<sum,則sum保持原值,不更新。。July、10/31。<br />----------------------------------*/

      3、不少朋友看到上面的答案之後,認為上述思路2的代碼,沒有處理全是負數的情況,當全是負數的情況時,我們可以讓程式返回0,也可以讓其返回最大的那個負數,下面便是前幾日重寫的,修改後的處理全是負數情況(返回最大的負數)的代碼:

//copyright@ July<br />//July、updated,2011.05.25。<br />#include <iostream.h><br />#define n 4 //多定義了一個變數</p><p>int maxsum(int a[n])<br />//於此處,你能看到上述思路2代碼(指標)的優勢<br />{<br /> int max=a[0]; //全負情況,返回最大數<br /> int sum=0;<br /> for(int j=0;j<n;j++)<br /> {<br /> if(sum>=0) //如果加上某個元素,sum>=0的話,就加<br /> sum+=a[j];<br /> else<br /> sum=a[j]; //如果加上某個元素,sum<0了,就不加<br /> if(sum>max)<br /> max=sum;<br /> }<br /> return max;<br />}</p><p>int main()<br />{<br /> int a[]={-1,-2,-3,-4};<br /> cout<<maxsum(a)<<endl;<br /> return 0;<br />}

      4、DP解法的具體方程:@ flyinghearts:設sum[i] 為前i個元素中,包含第i個元素且和最大的連續子數組,result 為已找到的子數組中和最大的。對第i+1個元素有兩種選擇:做為新子數組的第一個元素、放入前面找到的子數組。
sum[i+1] = max(a[i+1], sum[i] + a[i+1])
result = max(result, sum[i])
 

擴充:
1、如果數組是二維數組,同樣要你求最大子數組的和列?
2、如果是要你求子數組的最大乘積列?
3、如果同時要求輸出子段的開始和結束列?

第二節、Data structures and Algorithm analysis in C

下面給出《Data structures and Algorithm analysis in C》中4種實現。

//感謝網友firo<br />//July、2010.06.05。</p><p>//Algorithm 1:時間效率為O(n*n*n)<br />int MaxSubsequenceSum1(const int A[],int N)<br />{<br />int ThisSum=0 ,MaxSum=0,i,j,k;<br />for(i=0;i<N;i++)<br />for(j=i;j<N;j++)<br />{<br />ThisSum=0;<br />for(k=i;k<j;k++)<br />ThisSum+=A[k];</p><p>if(ThisSum>MaxSum)<br />MaxSum=ThisSum;<br />}<br />return MaxSum;<br />}</p><p>//Algorithm 2:時間效率為O(n*n)<br />int MaxSubsequenceSum2(const int A[],int N)<br />{<br />int ThisSum=0,MaxSum=0,i,j,k;<br />for(i=0;i<N;i++)<br />{<br />ThisSum=0;<br />for(j=i;j<N;j++)<br />{<br />ThisSum+=A[j];<br />if(ThisSum>MaxSum)<br />MaxSum=ThisSum;<br />}<br />}<br />return MaxSum;<br />}</p><p>//Algorithm 3:時間效率為O(n*log n)<br />//演算法3的主要思想:採用二分策略,將序列分成左右兩份。<br />//那麼最長子序列有三種可能出現的情況,即<br />//【1】只出現在左部分.<br />//【2】只出現在右部分。<br />//【3】出現在中間,同時涉及到左右兩部分。<br />//分情況討論之。<br />static int MaxSubSum(const int A[],int Left,int Right)<br />{<br />int MaxLeftSum,MaxRightSum; //左、右部分最大連續子序列值。對應情況【1】、【2】<br />int MaxLeftBorderSum,MaxRightBorderSum; //從中間分別到左右兩側的最大連續子序列值,對應case【3】。<br />int LeftBorderSum,RightBorderSum;<br />int Center,i;<br />if(Left == Right)Base Case<br />if(A[Left]>0)<br />return A[Left];<br />else<br />return 0;<br />Center=(Left+Right)/2;<br />MaxLeftSum=MaxSubSum(A,Left,Center);<br />MaxRightSum=MaxSubSum(A,Center+1,Right);<br />MaxLeftBorderSum=0;<br />LeftBorderSum=0;<br />for(i=Center;i>=Left;i--)<br />{<br />LeftBorderSum+=A[i];<br />if(LeftBorderSum>MaxLeftBorderSum)<br />MaxLeftBorderSum=LeftBorderSum;<br />}<br />MaxRightBorderSum=0;<br />RightBorderSum=0;<br />for(i=Center+1;i<=Right;i++)<br />{<br />RightBorderSum+=A[i];<br />if(RightBorderSum>MaxRightBorderSum)<br />MaxRightBorderSum=RightBorderSum;<br />}<br />int max1=MaxLeftSum>MaxRightSum?MaxLeftSum:MaxRightSum;<br />int max2=MaxLeftBorderSum+MaxRightBorderSum;<br />return max1>max2?max1:max2;<br />}</p><p>//Algorithm 4:時間效率為O(n)<br />//同上述第一節中的思路3、和4。<br />int MaxSubsequenceSum(const int A[],int N)<br />{<br />int ThisSum,MaxSum,j;<br />ThisSum=MaxSum=0;<br />for(j=0;j<N;j++)<br />{<br />ThisSum+=A[j];<br />if(ThisSum>MaxSum)<br />MaxSum=ThisSum;<br />else if(ThisSum<0)<br />ThisSum=0;<br />}<br />return MaxSum;<br />}   

本章完。

3.3續、求給定區間內的第K小(大)元素
第九章、閑話鏈表追趕問題
第十章、如何給10^7個資料量的磁碟檔案排序

著作權,本人對本blog內所有任何內容享有著作權及著作權。實要轉載,請以連結形式註明出處。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.