最大字串和问题 个人剖析

来源:互联网 发布:手机c语言程序编写软件 编辑:程序博客网 时间:2024/04/30 15:50
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保存,而且还省去最后遍历求最大的过程,这两步优化是同时进行的。

今天刷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)
0 0
原创粉丝点击