#2019121200026 最大子序列和

题目描述

给定一段序列,从\(a[1]\)\(a[n]\),求满足条件的\(1\leq i\leq j\leq n\),使得\(\sum\limits^j_{k=i}a[k]\)最大.

题解

1

最简单最容易想到的就是根据定义来枚举。
枚举上下界\(\{(i,j) | 1\leq i\leq j\leq n\}\),维护一个\(\max\)值即可。
其中枚举上下界的时间复杂度为\(O(n^2)\),求区间和的复杂度为\(O(n)\),所以总时间复杂度为\(O(n^3)\)

for ( int i = 1 ; i <= n ; i++ )
    for ( int j = i ; j <= n ; j++ )
        ans = max(ans,accumulate(a+i,a+j+1,0));

2

其实就是第一种方法的优化。
这里有个很容易想到的优化,即预处理出前缀和\(sum[i]=\sum\limits_{h=1}^ia[h]\),算区间和的时候即可将求区间和的复杂度降到\(O(1)\),枚举上下界的复杂度不变,所以总时间复杂度为\(O(n^2)\)

for ( int i = 1 ; i <= n ; i++ )
    sum[i]=sum[i-1]+a[i];
for ( int i = 1 ; i <= n ; i++ )
    for ( int j = i ; j <= n ; j++ )
        ans = max(ans,sum[j]-sum[i-1]);

3

可以利用动态规划的思维来继续优化,得到一个线性的算法,也是最大连续区间和的标准算法
定义\(maxn[i]\)为以\(i\)为结尾的最大连续和,则很容易找到递推关系:\(maxn[i]=\max \{0,maxn[i-1]\}+a[i]\)
所以只需要扫描一遍即可,总时间复杂度为\(O(n)\)

for ( int i = 1 ; i <= n ; i++ )
{
    last = max(0,last)+a[i];
    ans = max(ans,last);
}

4

同样用到类似的思维。
首先也需要预处理出前缀和\(sum[i]\),可以推出\(ans=\max \{sum[i]-\min \{sum[j]\} | 0\leq j<i\leq n \}\)
而最小前缀和可以动态维护,所以总时间复杂度为\(O(n)\)

for ( int i = 1 ; i <= n ; i++ )
    sum[i]=sum[i-1]+a[i];
for ( int i = 1 ; i <= n ; i++ )
{
    ans = max(ans,sum[i]-minn);
    minn = min(minn,sum[i]);
}
posted @ 2019-12-12 20:21  刘子闻  阅读(185)  评论(1)    收藏  举报