问题描述:
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
.
问题解决:
运用分治算法
将数组从中间项拆成前中后三部分
用递归求出前后两部分的最大子数组之和
再从中间的数开始,分别向前后扫描,每次跟一个元素相加,找到最大的相加后的和
分成三部分后,要么最后的结果不包含中间项,即前后两部分的最大子数组之和有一个是我们要的结果;
要么包含中间项,则通过向前向后求和取最大值
最后只要取前后两部分最大子数组之和、包含中间项的最大值中的最大值就是我们要的结果
代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//简单粗暴的方法O(n^2)
/*int largest;
int sum = 0;
vector<int>::iterator iter1 = nums.begin();
vector<int>::iterator iter2;
largest = *iter1;
for(; iter1 != nums.end(); iter1++) {
sum = *iter1;
if(sum > largest) {
largest = sum;
}
for(iter2 = ++iter1; iter2 != nums.end(); iter2++) {
sum += *iter2;
if(sum > largest) {
largest = sum;
}
}
iter1--;
}
return largest;*/
//比较明智的方法O(n)
/*int sum = 0;
vector<int>::iterator iter1 = nums.begin();
int result = *iter1;
for(int i : nums) {
sum = max(sum+i,i);
result = max(sum,result);
}
return result;*/
//分治算法O(nlogn)
//若数组为空,返回0
if(nums.empty()) return 0;
//否则返回获取最大子数组之和的递归函数
else return getMax(nums, 0, nums.size() - 1);
}
//分别传的是原数组,子数组的左右两个下标
int getMax(vector<int>& nums, int left, int right) {
//若左下标大于等于右下标,则返回左下标的值,即子数组长度为1时
if(left >= right) return nums[left];
//得到中间项下标
int midn = left + (right - left)/2;
//递归得到左右两部分的最大子数组之和
int mleft = getMax(nums, left, midn-1);
int mright = getMax(nums, midn+1, right);
//定义包含中间项的最大子数组之和为中间项
int mmid = nums[midn], t = mmid;
//向前跟数组元素相加,保留最大的和
for(int i = midn-1; i >= left; i--) {
t += nums[i];
mmid = max(mmid, t);
}
//定义t为向前加的最大和
t = mmid;
//向后跟数组元素相加,保留最大的和,则得到包含中间项的最大的和
for(int i = midn+1; i <= right; i++) {
t += nums[i];
mmid = max(mmid, t);
}
//取三个部分的最大值
return max(mmid, max(mleft, mright));
}
};