最大子数组的和
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开始,要么就加上她前面的,那个大选哪个。式子:。再把Bi+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);
}
};