#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]);
}
要做就做南波万

浙公网安备 33010602011771号