最大子段和,二分法变异,动态规划

先描述“最大子段和”的概念,然后用分治法和动态规化来解决,最后添加一些功能。


对于n个元素的整数数列(可能还有负整数),求任意连续m个数(m<=n),使其和为最大。如果该子段均为负数,定义其和为0.

比如{-2 11 -4 13 -5 -2},的最大子段和为{11,-4,13},其和为20。


该问题不能采用简单的分治法来解决,比如上面的数组分成{-2,11,-4}和{13,-5,-2}后,一个子问题的解是11,另一个是13,然而都不可能达到最终解。

所以这个问题的两个子问题不是相互独立的,需要涉及子问题的交互。故采用变异的二分法来处理。

 int maxSub_binary(constv ector<int> &nums,int left,int right){

   if(left==right)return nums[left]> 0 ? nums[left]: 0;//处理只有一个数字的情况。

   int mid = (left + right)>> 1;//分为两部分

   int maxSum_left = maxSub_binary(nums,left,mid);//左边递归求解

   int maxSum_right = maxSub_binary(nums, mid +1, right);//右边递归求解

    //处理脚踩两条船的子段

   int leftSum(0);

   for(int i(mid), tmpSum(0); i >= left; --i) {

       tmpSum+= nums[i];

       if(tmpSum > leftSum)leftSum = tmpSum;

   }//for i

   int rightSum(0);

   for(int i(mid + 1), tmpSum(0); i <= right; ++i) {

       tmpSum+= nums[i];

       if(tmpSum > rightSum)rightSum = tmpSum;

   }//for i

    //比较子段和的大小,选择返回哪一部分的子段和

   int maxSum_twoParts = leftSum + rightSum;

   if(maxSum_twoParts < maxSum_left&&maxSum_right < maxSum_left)return maxSum_left;

   if(maxSum_twoParts < maxSum_right)return maxSum_right;

   return maxSum_twoParts;

}//maxSub_binary

如果分治法的子问题不能相互独立,也就是子问题相互重叠的情况,一般采用动态规划法来解决。

int maxSub_dp(const vector<int> &nums) {

   int ret(0);

   int len = (int)nums.size();

   vector<int> dp(len, 0);

   dp[0]=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];

       if(dp[i]> ret)ret = dp[i];

   }//for i

   return ret;

}//maxSub_dp


下面的代码在之前函数的基础上,进一步得到最大子段和的长度,注意长度信息的添加位置。

由于maxSub_len_binary的返回值用来返回最大子段和的值,只能将长度信息反映在一个引用参数curLen上了。

maxSub_len_dp也是类似处理。


int maxSub_len_binary(const vector<int> &nums,int left,int right,int &curLen) {

   if(left==right) {

       curLen= 1;

       returnnums[left]> 0 ? nums[left]: 0;

   }//if

   int mid = (left + right)>> 1;

   int leftLen(0);

   int maxSum_left = maxSub_len_binary(nums,left,mid, leftLen);

   int rightLen(0);

   int maxSum_right = maxSub_len_binary(nums, mid +1, right, rightLen);

   int leftSum(0), leftPartLen(0);

   for(int i(mid), tmpSum(0), tmpPartLen(0); i >= left;--i) {

       tmpSum+= nums[i];

       ++tmpPartLen;

       if(tmpSum > leftSum)leftSum = tmpSum, leftPartLen = tmpPartLen;

   }//for i

   int rightSum(0), rightPartLen(0);

   for(int i(mid + 1), tmpSum(0), tmpPartLen(0); i <= right;++i) {

       tmpSum+= nums[i];

       ++tmpPartLen;

       if(tmpSum > rightSum)rightSum = tmpSum, rightPartLen = tmpPartLen;

   }//for i

   int maxSum_twoParts = leftSum + rightSum;

   if(maxSum_twoParts < maxSum_left&&maxSum_right < maxSum_left) {

       curLen= leftLen;

       return maxSum_left;

   }//if

   if(maxSum_twoParts < maxSum_right) {

       curLen = rightLen;

       return maxSum_right;

   }//if

   curLen = leftPartLen + rightPartLen;

   return maxSum_twoParts;

}//maxSub_len_binary

 

int maxSub_len_dp(const vector<int> &nums,int &curLen) {

   int ret(0);

   int len = (int)nums.size();

   vector<int> dp(len, 0);

   dp[0] = nums[0];

   int tmpLen(1);

   for(int i(1); i < len; ++i) {

       if(dp[i - 1] > 0)dp[i] = dp[i - 1] +nums[i],++tmpLen;

       else dp[i] =nums[i], tmpLen = 1;

       if(dp[i] > ret)ret = dp[i],curLen =tmpLen;

   }//for i

   return ret;

}//maxSub_len_dp


Gentle Dong,Second Version,20170224

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值