【Leetcode刷题】---动态规划--53.最大子序和

题目描述: 最大子序和      
        给定一个序列(至少含有 1 个数),从该序列中寻找一个连续的子序列,使得子序列的和最大。

        例如,给定序列 [-2,1,-3,4,-1,2,1,-5,4],
        连续子序列 [4,-1,2,1] 的和最大,为 6。

扩展练习:

若你已实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
 

解:使用动态规划规划的思想,求一个序列中连续子序列的最大和,定义状态,定义一个数组dp[i],表示以第i个元素为结尾的当前连续子序列的最大和。dp[0]--dp[i-1]表示已经求出的以i-1为结尾的最大子序和。如果dp[i-1]<0,那么dp[i]加上前面长度任意子序和都会小于不加前面的子序和。状态转移方程为:

dp[i]=nums[i]   if dp[i-1]<=0

dp[i]=dp[i-1]+nums[i]   if dp[i-1]>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 maxNum=nums[0];
	for(int i=1;i<len;i++){
		if(dp[i-1]>0)
			dp[i]=dp[i-1]+nums[i];
		else
			dp[i]=nums[i];
		maxNum=max(dp[i],maxNum);
	}
	return maxNum;
}
};

分治法:

思路:假设数组下标有效范围是l到r,将数组分为左半部分下标为(l,mid-1)和右半部分下标为(mid+1,r)以及中间元素下标为mid,接下来递归求出左半部分的最大子序和:left=maxNum(nums,l,mid-1); 右半部分最大子序和right=maxNum(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 maxSum(nums,0,nums.size()-1);
}
int maxSum(vector<int>&nums,int l,int r)
{
	if(l>r)
		return INT_MIN;
	if(l==r)
		return nums[l];
	int mid=(l+r)/2;
	int leftMaxNum=maxSum(nums,l,mid-1);
	int rightMaxNum=maxSum(nums,mid+1,r);
	int maxNum=nums[mid];
	int temp=nums[mid];
	for(int i=mid-1;i>=l;i--){
		temp+=nums[i];
		maxNum=max(maxNum,temp);
	}
	temp=maxNum;
	for(int j=mid+1;j<=r;j++){
		temp+=nums[j];
		maxNum=max(maxNum,temp);
	}
	return max(max(leftMaxNum,rightMaxNum),maxNum);
}
};

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值