一、题目
求一数组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等等,用动态规划就很好的利用了这个关系。