剑指Offer-连续子数组的最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

示例1:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

本文选用分治法的思想解题,其实可以使用动态规划的。

 分而治之

分治算法的解题思路:先将问题分解为子问题;解决子问题后,再将子问题合并,解决主要问题。

使用分治法解此题:

  • 将数组分为2部分。例如[1,2,3,4]被分为[1,2]和[3,4];
  • 通过递归计算,得到左右两部分的最大子序列和是leftSum,rightSum;
  • 从数组中间开始从左右计算最大子序列crossSum;
  • 返回max(leftSum,rightSum,crossSum);

 

/*
分治法

分治模板:
1.定义基本问题;
2.将问题分解为子问题并递归解决子问题;
3.合并子问题的解以获得原始问题的解;

将nums由中点mid分为三种情况:
1.最大子串在左边;
2.最大子串在右边;
3.最大子串跨中点,左右都有;

当子串在左边或右边时,继续分中点递归分解到一个数为止,对于递归后横跨的子串,
再分治为左侧和右侧求最大子串,可使用贪心算法求最大子串值,再合并为原始的最大
子串值

*/
class Solution {
public:
    int maxSubArray(vector<int>& nums){
        assert(!nums.empty());
        return helper(nums,0,nums.size()-1);
    }

    int helper(vector<int>& nums,int left,int right){
        if(left==right) return nums[left];//分解到一个值时返回该值
        int mid=left+(right-left)/2;
        int leftSum=helper(nums,left,mid);
        int rightSum=helper(nums,mid+1,right);
        int croSum=crossSum(nums,left,mid,right);//横跨中点的最大值
        return max(max(leftSum,rightSum),croSum);
    }

    int crossSum(std::vector<int>& nums,int left,int mid,int right){
        if(left==right) return nums[left];

        //贪心算法求左边的最大值
        int leftSubsum=INT_MIN;
        int curSum=0;
        for(int i=mid;i>left-1;--i){
            curSum+=nums[i];
            leftSubsum=max(leftSubsum,curSum);
        }

        //贪心算法求右边最大值
        int rightSubsum=INT_MIN;
        curSum=0;
        for(int i=mid+1;i<right+1;++i){
            curSum+=nums[i];
            rightSubsum=max(rightSubsum,curSum);
        }
        return leftSubsum+rightSubsum;
    }
};

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上的追梦人

您的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值