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.
上述题目。
首先是O(n)解,利用动态规划。在每个位置要记录下当前位置的两个最大值:1)加到当前值得最大值和 2)当前的全局最大值
1)加到当前的最大值 要么是上一个位置的 1) 加上当前位置值,要么是当前位置值
2)全局最大值,要么是 本位置的 1), 要么是之前的 2)
因此,只需要两个变量来进行记录即可。
代码:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum2cur = nums[0];
int max2cur = nums[0];
int n = nums.size();
for(int i = 1; i < n;i++){
sum2cur = max(sum2cur + nums[i], nums[i]);
max2cur = max(max2cur, sum2cur);
}
return(sum2cur, max2cur);
}
};
第二是题目要求的 divide and conquer 解,如何分治,一般2分用的比较顺手,可以尝试。
1. 选取数组的中间位置 middle, 最大值要么在左边,要么在右边,要么是左边 + middle + 右边。
2. 1)如果最大值在左边,那么就对左边进行递归;要是在右边就对右边递归;
2)如果最大值包含 middle,那么 最大值得序列一定是 左边的 后缀 + middle + 右边的 前缀,找到这个最大的后缀和前缀即可
3.求出上述三种情况的之后,返回最大值即可。
代码:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
return helper(nums, 0, nums.size() - 1);
}
int helper(vector<int>& nums, int left, int right){
if(left >= right) return nums[left];
int middle = (left + right) / 2;
int leftmax = helper(nums, left, middle - 1);
int rightmax = helper(nums, middle + 1, right);
int suffix = 0;
int prefix = 0;
int tmp = 0;
for(int i = middle - 1; i >= left;i--){
tmp += nums[i];
if(tmp > suffix) suffix = tmp;
}
tmp = 0;
for(int i = middle + 1; i <= right; i++){
tmp += nums[i];
if(tmp > prefix) prefix = tmp;
}
return max(max(leftmax, rightmax), suffix + nums[middle] + prefix);
}
};
that's all