Maximum Subarray
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array?[?2,1,?3,4,?1,2,1,?5,4]
,
the contiguous subarray?[4,?1,2,1]
?has the largest sum =?6
.
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
求子串最大和,第一次看到這題是在sogou的筆試,當時手寫代碼,用了動態規劃,以為就OK,誰知道在LeetCode上一敲各種bug。。
不過,總的思想是沒有錯的,只是要注意的點比較多,雖然不是最優的解法,但也陳述一下吧。
leetcode394,LZ先把問題想了想,求子串和最大,那什么是子串?拿以上數組為例,我們把子串的兩邊劃出來。
?[?2,1,?3, | 4,?1,2,1, |?5,4]
1 class Solution { 2 public: 3 int maxSubArray(int A[], int n) { 4 if (n == 1) 5 return A[0]; 6 vector<int> fsum(n-1, 0), bsum(n-1, 0); 7 vector<bool> fflag(n-1, false), bflag(n-1, false); 8 int tsum = A[0]; 9 fsum[0] = A[0]; 10 fflag[0] = true; 11 12 for (int i = 1; i < n-1; ++i) { 13 tsum += A[i]; 14 if (tsum < fsum[i-1]) { 15 fsum[i] = tsum; 16 fflag[i] = true; 17 } else { 18 fsum[i] = fsum[i-1]; 19 } 20 } 21 tsum = A[n-1]; 22 bsum[n-2] = A[n-1]; 23 bflag[n-2] = true; 24 for (int i = n-2; i > 0; --i) { 25 tsum += A[i]; 26 if (tsum < bsum[i]) { 27 bsum[i-1] = tsum; 28 bflag[i-1] = true; 29 } else { 30 bsum[i-1] = bsum[i]; 31 } 32 } 33 tsum += A[0]; 34 int ret = tsum; 35 for (int i = 0; i < n-1; ++i) { 36 int tmp = tsum - min(fsum[i], bsum[i]); // 只考慮左側或右側 37 if (!fflag[i] || !bflag[i]) { // 分隔線不重合 38 if (tmp < tsum - fsum[i] - bsum[i]) 39 tmp = tsum - fsum[i] - bsum[i]; 40 } else { // 分隔線重合 41 if (i > 0 && tmp < tsum - fsum[i-1] - bsum[i]) { 42 tmp = tsum - fsum[i-1] - bsum[i]; 43 } 44 if (i < n-2 && tmp < tsum - fsum[i] - bsum[i+1]) { 45 tmp = tsum - fsum[i] - bsum[i+1]; 46 } 47 } 48 if (tmp > ret) { 49 ret = tmp; 50 } 51 } 52 return ret; 53 } 54 };
成功拖低了平均水平,然后實在想知道有沒更好的方法,上網一搜果斷有的,找到了傳說中的Kadane算法(自行百度吧),代碼只有幾行(傷透了我的心。。),這里直接貼一下吧:
1 class Solution { 2 public: 3 int maxSubArray(int A[], int n) { 4 int ans = 0, maxn = INT_MIN; 5 for(int i = 0; i < n; i++){ 6 if(ans < 0) ans = 0; 7 ans += A[i]; 8 maxn = max(maxn, ans); 9 } 10 return maxn; 11 } 12 };
然后LZ蛋疼地去看下運行時間,發現居然比我的方法慢?不能理解。多提交了幾次,也是這樣,于是想了想,發現這代碼里面用了max函數,而且每次都要重要賦值,其實可以先判斷再賦值。LZ加了個判斷再賦值,然后提交,果斷快了,嗯,這是小插曲,大家可以不用管LZ自娛自樂。
然后就是分治的思路了,這個其實我也不太懂,不過看別人的代碼確實還是學了不少的,直接轉別人的代碼吧(以上Kadane算法也是別人的代碼)。
三個狀態:begin, end, mid=(begin+end)/2
leetcode121。1. 在A[begin..mid-1]間
2. 在A[mid+1..end]間
3. 包含A[mid]的區間
1 class Solution { 2 public: 3 int divide(int A[], int begin, int end) { 4 if (begin == end) return A[begin]; 5 if (begin + 1 == end) 6 return max(max(A[begin], A[end]), A[begin] + A[end]); 7 int mid = begin + (end - begin) /2; 8 int lmax = divide(A, begin, mid - 1); 9 int rmax = divide(A, mid + 1, end); 10 int mmax = A[mid]; 11 int tmp = A[mid]; 12 for (int i = mid-1; i >= begin; --i) { 13 tmp += A[i]; 14 if (tmp > mmax) 15 mmax = tmp; 16 } 17 tmp = mmax; 18 for (int i = mid+1; i <= end; ++i) { 19 tmp += A[i]; 20 if (tmp > mmax) { 21 mmax = tmp; 22 } 23 } 24 return max(max(lmax, rmax), mmax); 25 } 26 int maxSubArray(int A[], int n) { 27 return divide(A, 0, n-1); 28 } 29 };
代碼轉自http://blog.csdn.net/xshengh/article/details/12708291