input: int a[1..n], with positive and negative integers
output: the max sum of continuous integers, if all negative, return 0;
O(n^3):(具体计算见最下面)
max=0;
for starti=1->n
for leni=1->n-starti+1
sum=0;
for j=starti->starti+leni-1
sum+=a[j];
end
if(max<sum)//可以不用加完了在判断是否比当前最大值大,没加一次都判断,减少了清0操作
max=sum;
end
end
O(n^2):
max=0
for starti=1->n
sum=0;
for leni=1->n-starti+1
sum+=a[starti+leni-1];
if(max<sum)
max=sum;
end
end
O(n):DP
虽然之前上课学过,但是也知道用DP效率最高,但是今天再次写递推方程的时候还是会卡壳。
b[j]:a[1..j]中包含a[j]的最大字段和
b[j]=max{b[j-1]+a[j],a[j]}; 2<=j<=n
=a[j] j=1
(这里最容易忘记的一点是b[j]是表示包含a[j]的子问题最优解,而不是原始问题的子问题最优解。做完之后,再遍历一遍b[j]就可以求解最大值了)
1.递推的时候,判断b[j-1],>0 加上a[j],<0 赋上a[j],而且每次只许保存当前b[j],之前的1..j-1都不需要,因为已经把之前b[1..j-1]的最大用一个max记录下来了。
2.最后的遍历b[j]求最大,又可以优化,因为b[j]问题的最后解是从1->n递推过去的时候逐步保存的,并且始终记录当前最大即可
int b=0,max=0;
for j=1->n
if b>0
b+=a[j];
else
b=a[j];
end
if max<b
max=b;
end
end
这个算法经典在于:
本来DP需要保存b[1..n] 然后最后再遍历一遍求最大。但是可以用一个b保存,而且还省去最后遍历求最大的过程,这两步优化是同时进行的。
Proof:
O(n)^3
每次子序列求和,起始位置在1的有子序列长度有1,2,3.。。n,1+2+...+n
起始位置在2 2,3.。。n,2+...+n
起始位置在3 3.。。n,3+...+n
。。。
起始位置在n 1
通项an=1+..+n=n(n+1)/2
求Sn
Sn={1*2/2+2*3/3+...+n(n+1)}/2
={1*(1+1)+2*(2+1)+...+n(n+1)}/2//most important 技巧!!!!
={1^2+...n^2+1+2...+n}/2
={1/6*n(n+1)*(2*n+1)+n(n+1)/2}/2
=O(n^3)
output: the max sum of continuous integers, if all negative, return 0;
O(n^3):(具体计算见最下面)
max=0;
for starti=1->n
for leni=1->n-starti+1
sum=0;
for j=starti->starti+leni-1
sum+=a[j];
end
if(max<sum)//可以不用加完了在判断是否比当前最大值大,没加一次都判断,减少了清0操作
max=sum;
end
end
O(n^2):
max=0
for starti=1->n
sum=0;
for leni=1->n-starti+1
sum+=a[starti+leni-1];
if(max<sum)
max=sum;
end
end
O(n):DP
虽然之前上课学过,但是也知道用DP效率最高,但是今天再次写递推方程的时候还是会卡壳。
b[j]:a[1..j]中包含a[j]的最大字段和
b[j]=max{b[j-1]+a[j],a[j]}; 2<=j<=n
=a[j] j=1
(这里最容易忘记的一点是b[j]是表示包含a[j]的子问题最优解,而不是原始问题的子问题最优解。做完之后,再遍历一遍b[j]就可以求解最大值了)
1.递推的时候,判断b[j-1],>0 加上a[j],<0 赋上a[j],而且每次只许保存当前b[j],之前的1..j-1都不需要,因为已经把之前b[1..j-1]的最大用一个max记录下来了。
2.最后的遍历b[j]求最大,又可以优化,因为b[j]问题的最后解是从1->n递推过去的时候逐步保存的,并且始终记录当前最大即可
int b=0,max=0;
for j=1->n
if b>0
b+=a[j];
else
b=a[j];
end
if max<b
max=b;
end
end
这个算法经典在于:
本来DP需要保存b[1..n] 然后最后再遍历一遍求最大。但是可以用一个b保存,而且还省去最后遍历求最大的过程,这两步优化是同时进行的。
今天刷leetcode居然发现还犯了遍历b[j]来找maxsum的问题。。悲剧啊,都写过的东西。而且发现其实可以处理最大和为负数的情况,而不需要返回一个0
附属代码:
int maxSubArray(int A[], int n) {
int b=A[0],sum=b;
for(int i=1;i<=n-1;i++)
{
if(b>0)
b+=A[i];
else
b=A[i];
if(sum<b)
sum=b;
}
return sum;
}
Proof:
O(n)^3
每次子序列求和,起始位置在1的有子序列长度有1,2,3.。。n,1+2+...+n
起始位置在2 2,3.。。n,2+...+n
起始位置在3 3.。。n,3+...+n
。。。
起始位置在n 1
通项an=1+..+n=n(n+1)/2
求Sn
Sn={1*2/2+2*3/3+...+n(n+1)}/2
={1*(1+1)+2*(2+1)+...+n(n+1)}/2//most important 技巧!!!!
={1^2+...n^2+1+2...+n}/2
={1/6*n(n+1)*(2*n+1)+n(n+1)/2}/2
=O(n^3)