版权声明:未经博主同意,禁止转载,联系方式qq2928013321 https://blog.csdn.net/weixin_42130471/article/details/81037849
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
思路:
代码:
动态规划:很简单,定义一个数组,dp[],dp[i]以第i个元素为结尾的一段最大子序和。求dp[i]时,假设前面dp[0]~dp[i-1]都已经求出来了,dp[i-1]表示的是以i-1为结尾的最大子序和,若dp[i-1]小于0,则dp[i]加上前面的任意长度的序列和都会小于不加前面的序列(即自己本身一个元素是以自己为结尾的最大自序和)。举个例子:如-2,1,-3,4数组,dp[0]=-2;dp[1]=1(因为前一个dp[0]=-2<0,即(-2,1)子序和为-1,一个元素(1)子序和为1);dp[2]=dp[1]+nums[2]=1+(-3)=-2;dp[3]=4,因为dp[2]<0;
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len=nums.size();
if(len==0) return 0;
if(len==1) return nums[0];
vector<int>dp(len,0);
dp[0]=nums[0];
int max_num=dp[0];
int i=1;
for(;i<len;i++){
if(dp[i-1]>0)
dp[i]=dp[i-1]+nums[i];
else
dp[i]=nums[i];
max_num=max(dp[i],max_num);
}
return max_num;
}
};
方法二、分治法:
思路:假设数组下标有效范围是l到r,将数组分为左半部分下标为(l,mid-1)和右半部分下标为(mid+1,r)以及中间元素下标为mid,接下来递归求出左半部分的最大子序和:left=helper(nums,l,mid-1); 右半部分最大子序和right=helper(nums,mid+1,r);
接下来再将左半部分右边界,右半部分左边界以及中间元素nums[mid]整合,用了两个循环,先整合左半部分右边界和中间值,再将整合结果与右半部分左边界整合得到整合以后的最大子序和max_num,最后返回max_num,left,right的最大值即是要求的最大子序和。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==0)return 0;
return helper(nums,0,nums.size()-1);
}
int helper(vector<int>& nums,int l,int r){
if(l>r)return INT_MIN;//注意此处不是返回0,比如{-2,-1},分治以后变为左中右n{},-1,{-2}三部分。左半部分{}应返回INT_MIN,
//因为还要和右半部分的返回值进行比较,最终正确结果返回-1。若左半部分返回0,0>-2,且大于左中右的最大组合值(-1),最终结果返回0,出错
if(l==r)return nums[l];
int mid=(l+r)/2;
int left=helper(nums,l,mid-1);
int right=helper(nums,mid+1,r);
int t=nums[mid];
int max_num=nums[mid];
for(int i=mid-1;i>=l;i--){
t+=nums[i];
max_num=max(max_num,t);
}
t=max_num;
for(int i=mid+1;i<=r;i++){
t+=nums[i];
max_num=max(max_num,t);
}
return max(max(left,right),max_num);
}
};