1.题目
![](https://i-blog.csdnimg.cn/blog_migrate/bb82838479c15927c8d1a35b920da449.png)
2.题意
求最大子序列,follow up要求采用分治法
3.我的解法
int maxSubArray(int* nums, int numsSize) {
int ans=nums[0],i,sum=0;
for (i=0;i<numsSize;i++){
sum+=nums[i];
if(ans<sum)ans=sum;
if(sum<0)sum=0;
}
return ans;
}
优于100%
4.优秀解法
Kadane's Algorithm
该算法的思想就是,一个最大的子序列一定是这样的:当进入一个新的值时,判断一下这个值与之前的元素和
的大小关系,如果这个值更大,说明之前的元素和没有意义,应该抛弃不用,直接从这个值开始,这样一个
判断就确定了目前的最大值即,不是当前一个值就是之前元素和加上这个值。
而对于全局的最大值,就要每次来比较当前的最大值,把当前的最大值中真正最大的保留下来,也就是最后的
结果,这实际上是一种动态规划DP
int maxSubArray(int* nums, int numsSize) {
int maxSum = nums[0];
int sum = maxSum;
for(int i = 1; i < numsSize; i++){
sum += nums[i];
if (sum > maxSum) {
maxSum = sum;
}
if (sum < nums[i]) {
sum = nums[i];
}
if (maxSum < nums[i]) {
maxSum = nums[i];
sum = nums[i];
}
}
return maxSum;
}
c++的形式看的更直观
class Solution
{
public:
int maxSubArray(vector<int>& nums) {
int sum=nums[0],lgsum=nums[0];
for(int i=1;i<nums.size();i++)
{
sum=max(nums[i],sum+nums[i]);
lgsum=max(lgsum,sum);
}
return lgsum;
}
};
在本题中分治法的复杂程度更高,为nlogn,高于n,所以在这里只讨论一下分治法的大致思路
一个最大子序列有三种情况,要么在左半边,要么在右半边,要么跨越中线
先考虑在两边的情况,以左半边为例,右半边类似
递归的进行,缩小问题的规模,问题实际上又变成了一个只含左半边元素的,求最大子序列问题,所以左右进行递归即可
问题的最后都会变成求跨越中线的情况,这个情况就需要首先从中心开始,向两边延伸,先左后右,只要保证包含中点即可
最后得到最大的子序列,开始递归返回。分治法DC
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
return maxSub(nums, 0, n - 1);
}
private:
int maxSub(vector<int>& nums, int l, int r) {
if (l > r) return INT_MIN;
int m = l + ((r - l) >> 1);
int lm = maxSub(nums, l, m - 1); // left half
int rm = maxSub(nums, m + 1, r); // right half
int i, sum, ml = 0, mr = 0;
// Move leftwards
for (i = m - 1, sum = 0; i >= l; i--) {
sum += nums[i];
ml = max(sum, ml);
}
// Move rightwards
for (i = m + 1, sum = 0; i <= r; i++) {
sum += nums[i];
mr = max(sum, mr);
}
return max(ml + mr + nums[m], max(lm, rm));
}
};