【题目描述】洛谷1115最大连续子序列求和
给出一段序列,选出其中连续且非空的一段使得这段和最大。
【输入格式】
第1行是一个正整数N(N≤200000),表示了序列的长度。
第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列。
【输出格式】
输出仅包括1个整数,为最大的子段和是多少。子段的最小长度为1。
解题方案:
- 暴力枚举O(n3)
- 枚举——前缀和优化O(n2)
- 枚举——再优化O(n)
- 分治O(nlog2n)
- 动态规划O(n)
对于此问题的求解与优化,让人不得不折服于算法的魅力我就是这么入坑的。
1.暴力枚举
大多数题目不出意外第一想法基本都是枚举;对于这个题目的暴力其实不难想到,题目求解的是一个连续区间的和,区间必然有左右端点,因此直接枚举左端点L和右端点R,知道区间了求和还不是分分钟的事(循环累加呗),代码大概长得如下:
for(int L=1;L<=n;L++)//枚举左端点
for(int R=L;R<=n;R++){
//枚举右端点
int s=0;
for(int i=L;i<=R;i++)//求和L到R之间的数字的和
s+=arr[i];
ans=max(ans,s);
}
其实很多算法不需要实现,通过时空复杂度分析即可;不难看出该算法时间复杂度高达O(n3),,当n规模超过1000就会TLE。不过该算法还可以通过“前缀和”优化。
2.枚举——“前缀和”优化
前缀和:与数组arr声明一个一样大的数组sum,将arr的前i项和保存到sum[i],不难得到sum[i]=sum[i-1]+arr[i]
例如:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|
arr | 1 | 3 | -3 | 4 | 2 | -2 | 7 | -3 |
sum | 1 | 4 | 1 | 5 | 7 | 5 | 12 | 9 |
应用前缀和求解arr[ L到R ]的和:
sum[R]-sum[L-1] = arr[L]+arr[L+1]+……+arr[R]
因此,可以先预处理出前缀和,然后用sum[R]-sum[L-1]代替for L to R求和;可优化到O(n2)。分析后发现该时间复杂度依然不能满足题目要求,当然前缀和思想还是不错的,代码大概如下:
sum[0]=0;
for(int i=1;i<=n;i++)sum[i]=sum[i-