最大子序列和
来源:互联网 发布:企业即时聊天软件 编辑:程序博客网 时间:2024/05/18 18:56
这次我们来谈一谈最大子序列和问题。
问题描述如下:
给定一个长度为n的序列,其中既有正数又有负数,要求找到一个长度最少为1的子序列,使得这个子序列中所有元素的和是所有子序列中最大的。
例:3, -5, 7, -2, 8
其中最大的子序列和是7+(-2)+8=13
描述非常简单,最先想到的暴力做法是枚举子序列的位置,计算和,最后找到所有和中最大的。对于长度为
int a[MAXN];for (int i = 1; i <= n; ++i) cin >> a[i]; //读入int ans = -INF; //维护子序列和的最大值for (int i = 1; i <= n; ++i) //子序列的起点 for (int j = i; j <= n; ++j) {//子序列的终点 int sum = 0; //当前子序列和 for (int k = i; k <= j; ++k) sum += a[k]; //计算子序列和 if (ans < sum) ans = sum; //维护最大值 }//最终结果为ans
但是,如此高的时间复杂度无法让人满意。我们来做一点简单的优化:前缀和。原理很简单,用一个新的数组sum
来记录前缀和,其中
int a[MAXN], sum[MAXN] = {0};for (int i = 1; i <= n; ++i){ cin >> a[i]; //读入 sum[i] = sum[i - 1] + a[i]; //计算前缀和}int ans = -INF; //维护子序列和的最大值for (int i = 1; i <= n; ++i) //子序列的起点 for (int j = i; j <= n; ++j) //子序列的终点 ans = max(ans, sum[j] - sum[i - 1]);//最终结果为ans
那么我们能不能继续优化呢?只要还采用枚举子序列起点终点的办法,时间复杂度至少就是%O(n^2)%。然而,我们可以采用动态规划的思想。
依然用ans
来维护当前子序列和的最大值,同时用MinSum
来记录已经扫过的子序列和的最小值。这样,我们可以得到状态转移方程:
同时维护MinSum的值:
这样只需要一遍循环,时间复杂度为
int sum[MAXN] = {0};for (int i = 1; i <= n; ++i){ cin >> sum[i]; //读入 sum[i] = sum[i - 1] + a[i]; //计算前缀和}//注意:这里把a和sum合成为一个数组,因为a在状态转移方程中没有出现int ans = sum[1]; //维护子序列和的最大值int MinSum = sum[1]; //已经扫过的子序列和的最小值for (int i = 2; i <= n; ++i){ ans = max(ans, sum[i] - MinSum); MinSum = min(MinSum, sum[i]); //更新最小值}//最终结果为ans
这里结合一开始给出的数据3, -5, 7, -2, 8
作简单的推演。
数据的前缀和数组为:3, -2, 5, 3, 11
。
一开始ans
和MinSum
都被置为sum[1]
(想一想如果还像原来那样,ans=-INF
,MinSum=INF
并且第一次循环i=1
会有什么后果),第一次循环i=2。这时sum[i]-MinSum=-5>ans,ans
不更新。但MinSum
更新为-2,由3+(-5)得到。
第二次循环i=3。sum[i]-MinSum=7>3=ans,ans
更新为7,当前最大和是a[3]=7(虽然没有数组a,为了方便,我们仍然用a[i]来表示第i个数)。MinSum
不更新。
第三次循环i=4。sum[i]-MinSum=5<7=ans,ans
不更新。MinSum
也不更新。这表示,前四个数中,最大子序列和为a[3]=7。
第四次循环i=5。sum[i]-MinSum=13>7=ans,ans
更新为13,由a[3]+a[4]+a[5]得到。MinSum
不更新。
这样循环结束,得到最终答案13。
到这里,因为仅仅读入数据就是sum[i]
,那么边读入边处理是一个很好的选择。实现如下:
int a; //相当于原来的a[i]int sum = a; //前缀和int ans = a; //维护子序列和的最大值int MinSum = a; //已经扫过的子序列和的最小值for (int i = 1; i <= n; ++i){ cin >> a; sum += a; //计算前缀和 ans = max(ans, sum - MinSum); MinSum = min(MinSum, sum); //更新最小值}//最终结果为ans
至此,我们已经找到了最大子序列和问题的最优解:时间复杂度
最后说一下,有些文章中写“当sum<0的时候,前面的序列一定不是最优解的前缀”。在本文所述的问题中,可能出现非正数序列的情况,因此这个论断不适用。
- 最大子序列和
- 最大子序列和
- 最大和子序列
- 最大子序列和
- 最大子序列和
- 最大子序列和
- 最大子序列和
- 最大子序列和?
- 最大子序列和
- 最大子序列和
- 和最大子序列
- 最大子序列和
- 最大子序列和
- 最大子序列和
- 最大子序列和
- 最大子序列和
- 最大和子序列
- 最大子序列和
- 蜜汁最大完全平方数
- 166. Fraction to Recurring Decimal
- Android 使用多线程来做多文件上传Or下载
- Mac创建一个IPV6 Wifi热点
- Light Oj-1245
- 最大子序列和
- Qt::ConnectionType 解析
- 实测 c# .net 中 httpwebrequest 和 httpclient 性能 区别 对比
- Linux下MySQL的简单使用(3)
- JAVA数组
- 面对对象之封装及其好处
- CS231n课程笔记--线性分类
- 数组和指针的区别、字符数组和字符串指针区别
- Servlet中的web.xml