1. 程式人生 > >算法設計--在數組中找求和最大的連續子串

算法設計--在數組中找求和最大的連續子串

find 開始 所有 特殊情況 body 重置 clas -- 原理

問題:輸入具有n個整數的向量arr,輸出向量的任意連續子向量和的最大值

特殊情況(1、當向量都為正數時,為整個向量

     2、當向量都為負數時,為0,即空子串

    )

1、O(n2)的算法 (循環對所有情況進行遍歷)

 1 #include <stdio.h>
 2 #define max(a,b) ((a>b)?a:b)
 3 #define max3(a,b,c) ((a>b)?((a>c)?a:c):((b>c)?b:c))
 4 
 5 int find1(int arr[], int n){
 6     int i,j,sum,maxsofar;
 7     maxsofar = 0;
 8 
 9     for(i=0; i<n; i++){
10         sum = 0;
11         for(j=i; j<n; j++){
12             sum += arr[j];
13             maxsofar = max(sum, maxsofar);   
14         }
15     }
16     return maxsofar;
17 }

其中有個小細節就是 註意sum(i, j-1) 和 sum(i, j)的關系,不要每次在求和的時候從頭(i的位置)開始,那樣會使復雜度變為O(n3)


2、O(nlogn)算法

基於分治原理的算法:首先將n的原問題劃分為大小基本相等的兩個子問題,我們分別稱為a和b子問題,可以遞歸找出a和b問題的最大子向量,稱為maxa 和 maxb。

但他們兩個之間的最大值不一定使我們求得n問題的最優解,還有一種可能是跨越a和b的邊界,我們稱之為c,c情況的最優解為maxc。

那麽問題變成了如何求解maxc?

我們可以發現,maxc中在a的部分為a中包括a的右邊界的最大值,maxc中在b的部分為b中包括b的左邊界的最大值,因此可以在O(N)的時間內算出maxc

因此得到T(N) = 2T(N/2) + O(N)

推導得到T(N) = O(nlogn)

 1 int find2(int arr[], int s_p, int e_p){
 2     int m, sum, i, maxsofar, lmaxsofar, rmaxsofar;
 3     maxsofar = 0;
 4 
 5     if(s_p == e_p){
 6         return maxsofar;
 7     }
 8     else if(s_p == e_p){
 9         return max(arr[s_p],0);
10     }
11     else{
12         m = (s_p + e_p) / 2;
13 
14         lmaxsofar = 0;
15         sum = 0;
16         for(i=m; i>=s_p; i--){
17             sum += arr[i];
18             lmaxsofar = max(sum, lmaxsofar);
19         }
20 
21         rmaxsofar = 0;
22         sum = 0;
23         for(i=m+1; i<=e_p; i++){
24             sum += arr[i];
25             rmaxsofar = max(sum, rmaxsofar);
26         }
27 
28         return max3(lmaxsofar+rmaxsofar,find2(arr, s_p, m), find2(arr, m+1, e_p));
29     }
30 }

3、O(n)算法

先上代碼,代碼非常簡短,理解起來比較困難,但是執行效率非常高

 1 int find3(int arr[], int n){
 2     int i,maxsofar,maxendinghere;
 3     maxsofar = 0;
 4     maxendinghere = 0;
 5     
 6     for(i=0; i<n; i++){
 7         maxendinghere = max(maxendinghere + arr[i], 0);
 8         maxsofar = max(maxsofar, maxendinghere);
 9     }
10 
11     return maxsofar;
12 }

假設我們已經解決了x[0,n-1]的問題,利用分治算法的原理:前i個元素中,最大總和子數組要麽在前i-1個元素中,要麽其結束位置在i處。

分析其結束為止在i處的情況,那麽子向量中除去i處的元素組成的子向量一定是x[0,i-1]中結束位置為i-1的最大子向量。

看代碼中的關鍵變量為maxendinghere:在循環語句的第一個賦值語句之前,maxendinghere是結束位置為i-1的最大子向量的和;賦值語句將其修改為結束位置為i的最大子向量的和。若加上x[i]後結果依然為正值,則結束位置在i的最大子向量值就為maxendinghere+x[i],如果為負值,則重置為0。

算法設計--在數組中找求和最大的連續子串