Leetcode#53 Maximum Subarray


原題地址

 

方法I:動態規划

另sum[i]表示從i開始的最大子串和,則有遞推公式:sum[i] = max{A[i], A[i] + sum[i+1]}

因為遞推式只用到了后一項,所以在編碼實現的時候可以進行狀態壓縮,用一個變量即可

代碼:

 1 int maxSubArray(int A[], int n) {
 2   int sum = A[n - 1];
 3   int maxSum = sum;
 4 
 5   for (int i = n - 2; i >= 0; i--) {
 6     sum = max(A[i], sum + A[i]);
 7     maxSum = max(maxSum, sum);
 8   }
 9 
10   return maxSum;
11 }

時間復雜度O(n),空間復雜度O(1)

 

方法II:掃描法(姑且這么稱呼吧)

這是網上比較流行的一種做法,本質上還是動態規划+狀態壓縮。參考這篇博文

代碼:

 1 int maxSubArray(int A[], int n) {
 2   if (n == 0)
 3     return 0;
 4 
 5   int max_ending_here = A[0];
 6   int max_so_far = A[0];
 7   for(int i = 1; i < n; ++i)
 8     {
 9       if (max_ending_here < 0)
10         // So far we get negative values, this part has to be dropped
11         max_ending_here = A[i];
12       else
13         // we can accept it, it could grow later
14         max_ending_here += A[i];
15 
16       max_so_far = max(max_so_far, max_ending_here);
17     }
18   return max_so_far;
19 }

時間復雜度O(n),空間復雜度O(1)

 

方法III:分治法

假設求A[l..r]的最大子串和

首先將其分成兩半A[l..m]和A[m+1..r],其中m=(l+r)/2,並分別求遞歸求出這兩半的最大子串和,不妨稱為left,right。如下圖所示:

A[l..r]的連續子串和可能出現在左半邊(即left),或者可能出現在右半邊(即right),還可能出現在橫跨左右兩半的地方(即middle),如下圖橙色部分所示:

當然,middle完全有可能覆蓋left或right,它可能的范圍入下圖所示:

那么,如何求middle?貌似沒有什么簡單的方法,只能從中間向兩遍掃,也就是把上圖種的范圍掃一遍。具體怎么掃呢?見方法I和方法II

是不是突然覺得很坑爹?既然知道最后求middle要掃一遍,還不如一開始就從l到r掃一遍求max得了,還費什么勁兒求left和right呢?求left和right的作用僅限於縮小掃描的范圍。

代碼:

 1 int diveNConquer(int A[], int l, int r) {
 2   if (l == r)
 3     return A[l];
 4 
 5   int m = (l + r) / 2;
 6   int left = diveNConquer(A, l, m);
 7   int right = diveNConquer(A, m + 1, r);
 8   int middle = A[m];
 9   for (int i = m - 1, tmp = middle; i >= l; i--) {
10     tmp += A[i];
11     middle = max(middle, tmp);
12   }
13   for (int i = m + 1, tmp = middle; i <= r; i++) {
14     tmp += A[i];
15     middle = max(middle, tmp);
16   }
17 
18   return max(middle, max(left, right));
19 }
20 
21 int maxSubArray(int A[], int n) {
22   return diveNConquer(A, 0, n - 1);
23 }

分析一下時間復雜度,設問題的工作量是T(n),則有T(n) = 2T(n/2) + O(n),解得T(n) = O(nlogn)。看看,效率反而低了不少。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM