LeetCode 53. Maximum Subarray

最大子数组的和


Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

Follow up:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

给一个array,计算它们和最大的子array。

我们可以知道遇到小于0的数,会变小;遇到大于0的数,会变大。


1. O(n)方法

维基百科有关于Kadane Algorithm的介绍,用了数学归纳法,这可以用于解决最大子数组和。

简单来说: Kadane 的算法是,如果之前的sum 小于0了,就重新计算sum,如果sum不小于0,那么继续加。

详细来说:记以第i个为结尾的最大和为Bi,以第i+1个为结尾的最大和为Bi+1,第i个为Ai。以新加进来的第i+1个结尾的最大和,要么就从新计算,从i+1开始,要么就加上她前面的,那个大选哪个。式子:B_{i+1} = max(A_{i+1},B_i)。再把Bi+1放到整体来比较,选择大的。式子:res = max(res,B_{i+1}) 。以此类推。

Python版本。

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res = nums[0]
        pre_sum = 0
        for i in nums:
            pre_sum = max(i,pre_sum+i)
            res = max(pre_sum,res)
        return res            

C++版本。(这个不是Kadane算法,但差不多意思,野生的)

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res=nums[0];
        int pre_sum = 0;
        for(int i=0;i<nums.size();i++){
            if(pre_sum<0){
                pre_sum = nums[i];
            }else{
                pre_sum += nums[i];
            }
            res = max(pre_sum,res);
        }
        return res;
    }
};

2. Divide和Conquer

有三种情况:

  • 最大和出现在左边
  • 最大和出现在右边
  • 最大和出现在中间

出现在左边一堆和出现在右边一堆好说。当左边/右边只有一个时,就是取那个数。其他的二分法可以得到结果。

如果是第三种情况,则考虑中间开始往两边的和,与左边,右边比较,选择大的。进行递归。有个解释的好的博客

C++代码。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    	if(nums.size()==0) return 0;
        return maxSubArraySum(nums, 0, nums.size()-1);
    }
    int maxSubArraySum(vector<int> &nums, int left, int right) {
        if (left == right) return nums[left];
        int mid = (left + right) / 2;
       	//left_mss左边一堆  right_mss右边一堆 
        int left_mss = maxSubArraySum(nums,left,mid);
        int right_mss = maxSubArraySum(nums,mid+1,right);
        
		//中间情况 
        int leftSum = INT32_MIN;
	    int rightSum = INT32_MIN;	 
		int sum = 0;
		//从中间往右求和 
		for(int i=mid+1;i<=right;i++){
			sum += nums[i];
			rightSum = max(rightSum,sum);
		} 
		
		sum = 0;
		//从中间往左求和 
		for(int i=mid;i>=left;i--){
			sum += nums[i];
			leftSum = max(leftSum,sum);
		}
		//比较左、右和中间 
		int res = max(left_mss,right_mss);
		return max(res,leftSum+rightSum);
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值