最大子数组问题【动态规划】

       昨天偶然上csdn,看到这个问题,学习了一种复杂度为O(n)的算法,可以计算Array的最大子数组问题。思路就是从0-length,将array累加起来,同时用一个变量max记录最大值,如果sum > max,就更新max,如果sum < 0 就令sum = 0(为什么是这样呢,sum < 0的话,前面的就可以直接舍弃了)。附上代码:


#include <iostream>
using namespace std;

void MaxSubArray(int array[], int len) {
  int sum = 0, max = array[0], s = 0, s_pos = 0, e_pos = 0;
  for (int i = 0; i < len; i++) {
    sum += array[i];
    //sum > max 更新 max, 并把终点位置置为 i 
    if (sum > max) {
      e_pos = i;
      s_pos = s;
      max = sum;
    }
    //sum < 0的话,就该把前面的抛弃,并且重置sum 为 0, 起始位置为 i + 1 
    if (sum < 0) {
      sum = 0;
      s = i + 1;
    }
    //sum > 0,继续 (假设最大子数组在中间 array[i~j]
    //因为 array[k~i-1]的和大于0,则array[k~j]显然是更大的子数组) 因此 sum > 0时候,继续 
  }
  cout << "start position: " << s_pos << endl;
  cout << "end   position: " << e_pos << endl;
  cout << "max value: " << max << endl;
}

int main()
{
int A[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
MaxSubArray(A, sizeof(A)/sizeof(int));
system("pause");
return 0;
}



这个还记录了位置,真是短小而精悍的代码,我是看这里的评论的http://blog.csdn.net/xjm199/article/details/17954997#comments然后改了下代码而已

      接着又看到一篇动态规划的最大子数组问题http://blog.csdn.net/xjm199/article/details/17953753,看了下,觉得这跟上面的方法就是一样的,那个dp[i]也不是记录着dp[0~i]的最大子数组问题,于是我就想用dp[i]记录dp[0~i]的最大子数组问题值,用动态规划,就是考虑当前的array[i]是不是最大子数组的一员,如果是要怎么做,不是要怎么做,代码如下:

#include <iostream>
#define SIZE 9
using namespace std;

void MaxSubArray(int array[], int dp[], int len) {
  dp[0] = array[0];           //只有一个元素时,dp[0]显然为array[0] 
  int end_position = 0;       //记录最大子数组末尾点 
  for (int i = 1; i < len; i++) {
    int max = array[i], sum = 0, sum2 = 0, j, s0 = i, st = i, en = i;
    /*这个for循环是表示子数组要包括Array[i],则从i到end_position
    看看此数组的中最大子数组和为多少*/ 
    for (j = i; j > end_position; j--) {
      sum += array[j];
      sum2 += array[j];
      if (sum > max) {
        max = sum;
        en = j;
        st = s0;
      }
      if (sum < 0) {
        sum = 0;
        s0 = j + 1;
      }
    }
    //sum2>0 && dp[i-1] + sum2 > max,则array[end_position~i]与array[0~i]合并才是当前数组最大子数组值 
    if (sum2 > 0 && dp[i-1]+sum2 > max) {
      dp[i] = dp[i-1]+sum2;
      end_position = st;
    } else if (dp[i-1] > max) {     //不能合并时,让dp[i]等于dp[i-1]和max的大者 
        dp[i] = dp[i-1];
    } else {
        dp[i] = max;
        end_position = st;
    }
  }
  for (int i = 0; i < len; i++)
    cout << dp[i] <<  ' ';
}
int main() {
  int A[] = {18, 20, -7, 12, -5, -22, 15, -4, 7};
  int dp[SIZE];
  MaxSubArray(A, dp, SIZE);
  system("pause");
  return 0;
}


array[]= {18, 20 , -7, 12} ,dp[2] = 38, end_position = 1(最大子数组的末尾下标, dp[2]表示array[0-2]的子数组最大值),则dp[3]的求法为,先看看-7+12 是否是大于0的,如果大于0,则18 20 -7 12合并后显然比dp[2]更大,应该合并,这时也得找出-7 12 这个数组最大子数组值,显然是12,拿12和合并后的比较取较大者,然后更新end_position。继续循环

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值