From 94b629d5908f6278290593caf30725491d9ba3c9 Mon Sep 17 00:00:00 2001 From: pezy_mbp Date: Fri, 10 Apr 2015 00:42:25 +0800 Subject: [PATCH] improving the style of 014 --- 014. Maximum Subarray/README.md | 36 +++++++++++++++++++++- 014. Maximum Subarray/divide_conquer.h | 27 +++++++++++++++++ 014. Maximum Subarray/main.cc | 8 ++--- 014. Maximum Subarray/solution.h | 41 -------------------------- 4 files changed, 65 insertions(+), 47 deletions(-) create mode 100644 014. Maximum Subarray/divide_conquer.h diff --git a/014. Maximum Subarray/README.md b/014. Maximum Subarray/README.md index 72e6077..daeb399 100644 --- a/014. Maximum Subarray/README.md +++ b/014. Maximum Subarray/README.md @@ -15,7 +15,7 @@ benefited = max(A[i], benefited + A[i]); maxv = max(benefited, maxv); ``` -聪明的你一定发现了,第一句条恰是**当权者的决策**,第二条恰是**历史学家的总结**。 横批:人类是贪婪的。 +聪明的你一定发现了,第一句条恰是**当权者的决策**,第二条恰是**历史学家的总结**。 横批:人类是贪婪的。 所以不要怪任何一方,从他们的立场看,都是最优解。局部最优能否导致整体最优呢? 千年谜题。 @@ -30,3 +30,37 @@ maxv = max(benefited, maxv); >If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle 咳咳咳, @Mooophy ,该出来了。。。 + +----- + +@Mooophy 应约而出,给出了[代码](#8),我根据其代码,尝试分析一下分治法的策略: + +分治法的灵魂在于一个 **"分"** 字。对于这道题而言,求`A`的最大和子序列,可以给`A`来一刀: + + −2,1,−3,4,−1,2,1,−5,4 + left | right + crossing + +由于子序列连续,它必然属于上述划分中的某一种情况: + +- 完全属于 left 部分 +- 完全属于 right 部分 +- 属于 crossing 部分(即跨越中点) + +于是其核心代码如下: + +```cpp +int maxSubArray(int A[], int l, int h) { + if (l == h) return A[l]; // 仅有一个数 + int m = (l + h) / 2; // 中点位置(划分点) + return std::max({maxSubArray(A, l, m), maxSubArray(A, m+1, h), maxCrossing(A, l, m, h)}); +} +``` + +是否非常的简洁呢? + +下面问题集中在 `maxCrossing` 的策略,这个过程可以线性求出。即将其属于 `left` 范畴的 `sum` 与属于 `right` 范畴的 `sum` 加起来即可。 + +实现代码请见:[divide_conquer.h](divide_conquer.h) + +这部分的详细思路可参考 CLRS 的第四章分治法的第一小节。 diff --git a/014. Maximum Subarray/divide_conquer.h b/014. Maximum Subarray/divide_conquer.h new file mode 100644 index 0000000..75d1f74 --- /dev/null +++ b/014. Maximum Subarray/divide_conquer.h @@ -0,0 +1,27 @@ +#include +#include + +class Solution { + int maxCrossing(int A[], int l, int m, int h) { + int left_max = INT_MIN, right_max = INT_MIN; + for (int i=m, sum=0; i >= l; --i) { + sum += A[i]; + if (left_max < sum) left_max = sum; + } + for (int i=m+1, sum=0; i <= h; ++i) { + sum += A[i]; + if (right_max < sum) right_max = sum; + } + return left_max + right_max; + } + + int maxSubArray(int A[], int l, int h) { + if (l == h) return A[l]; + int m = (l + h) / 2; + return std::max({maxSubArray(A, l, m), maxSubArray(A, m+1, h), maxCrossing(A, l, m, h)}); + } +public: + int maxSubArray(int A[], int n) { + return maxSubArray(A, 0, n-1); + } +}; diff --git a/014. Maximum Subarray/main.cc b/014. Maximum Subarray/main.cc index b8e08d7..f1a0a08 100644 --- a/014. Maximum Subarray/main.cc +++ b/014. Maximum Subarray/main.cc @@ -1,14 +1,12 @@ #include #include "solution.h" +//#include "divide_conquer.h" int main() { - int A[] = {-2,1,-3,4,-1,2,1,-5,4}; + int A[] = {-2,1,-3,4,-1,2,1,-5,4}; Solution s; std::cout << s.maxSubArray(A, 9) << std::endl; - SolutionByDivideAndConquer dac; - std::cout << s.maxSubArray(A, 9) << std::endl; - return 0; -} +} diff --git a/014. Maximum Subarray/solution.h b/014. Maximum Subarray/solution.h index bd0f72b..2e2d4f2 100644 --- a/014. Maximum Subarray/solution.h +++ b/014. Maximum Subarray/solution.h @@ -12,44 +12,3 @@ class Solution { return maxv; } }; - -class SolutionByDivideAndConquer{ - //O(n) - int find_max_crossing_subarray(int arr[], unsigned low, unsigned mid, unsigned hgh) - { - auto accumulation = 0; - - auto lft_sum = accumulation = arr[mid]; - if (mid > low) - for (auto i = mid - 1; i != low - 1; --i) - if ((accumulation += arr[i]) > lft_sum) - lft_sum = accumulation; - - auto rht_sum = accumulation = arr[mid + 1]; - if (hgh > mid) - for (auto i = mid + 2; i != hgh + 1; ++i) - if ((accumulation += arr[i]) > rht_sum) - rht_sum = accumulation; - - return lft_sum + rht_sum; - } - - //O(n lg n) - int divide_and_conquer(int arr[], unsigned low, unsigned hgh) - { - if (low == hgh) return arr[low]; - - auto mid = (low + hgh) / 2; - auto lft = divide_and_conquer(arr, low, mid); - auto rht = divide_and_conquer(arr, mid + 1, hgh); - auto crs = find_max_crossing_subarray(arr, low, mid, hgh); - - return std::max({ lft, rht, crs }); - } - -public: - int maxSubArray(int A[], int n) - { - return divide_and_conquer(A, 0, n - 1); - } -};