动态规划—1.1 数组最大连续子序列和

一、题目

  求一数组A[n]的最大连续子序列和,例如数组

A=[-2,1,-3,4,-1,2,1,-5,4]

  其中如下连续子数组的和最大,为6。

[4,-1,2,1]

二、思路

1、从后往前

  假设有数组Ai、Aj、Ak,有

Aj = [Ai,j]
Ak = [Aj,k]

  令Ai的最大连续子序列和为f(i),那么对于Aj来说有

f(j) = max(f(i), f(i)+j, j)

  如果按照这个思路,则Ak有

f(k) = max(f(j), f(j)+k, k)

  假设f(j)=f(i),那么对于Ak来说,显然f(j)+k不是连续子序列。所以必须在方程中拿掉f(i),但又不能不比较它的大小。
  令g(i)为Ai的包含最右边元素的最大连续子序列和,那么Aj的包含最右边元素的最大连续子序列和为

g(j) = max(g(i)+j, j)

  则有

f(j) = max(g(j), f(i))

  同理,对于Ak

g(k) = max(g(j)+k, k)    f(k) = max(g(k), f(j))

  同样的假设f(j)=f(i),这时f(k)中不再出现非连续子序列的情况。

2、从前往后

  数组A0=[a],a是解,有f(0)=max(a)。
  数组A1=[A0,b],需要比较a、b、a+b,有

f(1) = max(a, b, a+b)
// 把f(0)带入,有
f(1) = max(f(0), b, f(0)+b)

  数组A2=[A1,c],需要比较a、b、c、a+b、b+c、a+b+c。假设

x2 = max(x1, c, x1+c)

  假设f(1)=a,即a>(b,a+b),f(2)=max(a,c,a+c)。由a>(b,a+b)可知a+c>(b+c,a+b+c),虽然需要比较的连续子数组的关系可知,但是里面还比较了a+c,这显然不符合要求。
  假设f(1)=b,即b>(a,a+b),f(2)=max(b,c,b+c)。由b>(a,a+b)可知b+c>(a+c,a+b+c),同样的也是上述结论。
  假设f(1)=a+b,即a+b>(a,b),f(2)=max(a+b,c,a+b+c)。由a+b>(a,b)可知a+b+c>(a+c,b+c),同样的也是上述结论。
  故上述对x1的每种可能的情况都进行了讨论,虽然都可以知道需要比较的连续子数组的关系,但是多出来了非连续子数组的情况,所以状态转化方程是不对的。
  故需要对上述状态转化方程进行修改。
  数组A0=[a],a是解,有f(0)=max(a),g(0)=max(a)
  数组A1=[A0,b],需要比较a、b、a+b,有

g(1) = max(a+b, b)
// 把g(0)带入,有
g(1) = max(g(0)+b, b)
f(1) = max(g(1), f(0))

  数组A2=[A1,c],需要比较a、b、c、a+b、b+c、a+b+c。有

g(2) = max(g(1)+c, c)
f(2) = max(g(2), f(1))

  假设g(1)=b,即b>a+b,g(2)=max(c,b+c),f(2)=max(a,c,b+c)。由b>a+b可知b+c>a+b+c。故所有连续子数组的关系可知。
  假设g(1)=a+b,即a+b>b,g(2)=max(c,a+b+c),f(2)=max(a,c,a+b+c)。由a+b>b可知a+b+c>b+c。故所有连续子数组的关系可知。
  此状态转化方程可以知道连续子数组的关系,同时也满足题目的要求。
  可以依次类推,每当数组的后面新加一个数,该状态方程可以把该数加进入进行比较,从而可以获取所有连续子数组的关系。

三、源码

  通过上述分析,可以状态转化方程为

g(i) = max(g(i-1)+i, i)
f(i) = max(g(i), f(i-1))
f(0) = A[0], g(0) = A[0]

  故代码为

int maxSubArray(int* nums, int numsSize)
{
    int max = nums[0];
    int g = nums[0];
    int i = 0;
    for(i=1; i<numsSize; i++)
    {
        g = (g+nums[i]>nums[i])?g+nums[i]:nums[i];
        max = (g>max)?g:max;
    }
    return max;
}

四、后话

  该题最笨的算法是枚举出所有的连续子数组,然后比较大小,例如A=[a,b,c,d],所有的连续子数组为

{a, b, c, d, a+b, b+c, c+d, a+b+c, b+c+d, a+b+c+d}

  而有n个元素的数组的所有连续子数组的个数为

n+(n-1)+(n-2)+...+1

  显然该算法的时间复杂度为O(n^2),不是最佳的算法。求最大连续子数组,肯定要知道每个连续子数组的大小关系,但这并不代表需要把每个连续子数组都直接单纯的比较一遍,因为他们有相互的联系,知道了某些连续子数组的大小关系,其他某些连续子数组的大小关系也就知道了。例如a+b>b,那么一定有a+b+c>b+c,一定有a+b+c+d>b+c+d等等,用动态规划就很好的利用了这个关系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值