问题

给定整数: A1,A2,…,An,
求∑jk=iAk 的最大值(为方便起见,假设全部的整数均为负数,则最大子序列和为0)

比如

对于输入:-2,11,-4,13,-5,-2,答案为20,即从A2到A4

分析

这个问题之所以有意思。是由于存在非常多求解它的算法。

解法一:穷举遍历

老老实实的穷举出全部的可能,代码例如以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//计算并返回所最大子序列的和:穷举遍历
int maxSubSum1(const vector<int> & a)
{
//用来存储最大子序列的和
int maxSum = 0; //i标记子序列的头
for (int i = 0; i < a.size(); i++)
{
//j标记子序列的尾
for (int j = i; j < a.size(); j++)
{
//用来存储当前头尾计算的求和结果
int thisSum = 0; //将子序列的值依次增加求和结果
for (int k = i; k <= j; k++)
{
thisSum += a[k];
} //存储两者的最大值
if(thisSum > maxSum)
maxSum = thisSum;
}
} return maxSum;
}

这是大多数人都会想到的方法:把全部的可能都列举出来,然后再把子序列的全部值都加起来求和。
简单粗暴的攻克了问题。并且还非常好理解。

这样的算法的时间复杂度为O(N3)。

解法二:穷举优化

事实上第三个for循环全然没有必要,在第二层for循环的时候就计算求得的和并且继续带入下一轮的for循环就可以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//计算并返回所最大子序列的和:穷举优化
int maxSubSum2(const vector<int> & a)
{
//用来存储最大子序列的和
int maxSum = 0; //i标记子序列的头
for (int i = 0; i < a.size(); i++)
{
//用来存储当前头尾计算的求和结果
int thisSum = 0; //j标记子序列的尾
for (int j = i; j < a.size(); j++)
{ //将子序列的值增加上次求和结果
thisSum += a[j]; //存储两者的最大值
if(thisSum > maxSum)
maxSum = thisSum;
}
} return maxSum;
}

这样的算法的时间复杂度为O(N2)。

解法三:分而治之

分而治之,顾名思义分为两个部分

  • 分:把大问题分成大致相等的两个子问题,然后递归的进行求解。
  • 治:把两个子问题的解合并到一起并再做少量的附加工作。

在最大子序列和的问题里,最大子序列的和可能出如今三个地方:

  • 整个出如今输入数据的左半部
  • 整个输入数据的右半部
  • 横跨左右两个部分

对于前两种能够递归求解,对于第三种,能够把左右两个部分的和分别求出,然后加在一起。
详细的代码例如以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//计算并返回所最大子序列的和:分而治之
int maxSubSum3(const vector<int> & a,int left,int right)
{
//基础情况:单个元素。直接返回这个数值或者0
if(left == right)
{
return a[left];
} //获取中点
int center = (left + right) / 2; /* 整个出如今输入数据的左半部的最大子序列求和 */
int leftMaxSum = maxSubSum3(a,left,center); /* 整个出如今输入数据的右半部的最大子序列求和 */
int rightMaxSum = maxSubSum3(a,center+1,right); //计算左右两个子序列求和结果的最大值
int lrMaxSum = max(leftMaxSum,rightMaxSum); /* 横跨左右两个部分的最大子序列求和 */ //从center向左处理左半边
int maxLeftSum = 0;
int leftSum = 0;
for (int i = center; i >= left; i--)
{
leftSum += a[i];
maxLeftSum = max(maxLeftSum,leftSum);
} //从center向右处理右半边
int maxRightSum = 0;
int rightSum = 0;
for (int j = center+1; j <= right; j++)
{
rightSum += a[j];
maxRightSum = max(maxRightSum,rightSum);
} //返回求和和前面算出结果的最大值
return max( lrMaxSum, maxLeftSum+maxRightSum);
}

这样的算法的时间复杂度为O(NlogN)。

解法四:联机算法

先来解释一下联机算法的概念:

联机算法:在随意时刻,算法对要操作的数据仅仅读入(扫描)一次,一旦被读入并处理,它就不须要在被记忆了。而在此处理过程中算法能对它已经读入的数据马上给出对应子序列问题的正确答案。

具有这样的特性的算法叫做联机算法(on-line algorithm)。

对于这个问题。代码例如以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//计算并返回所最大子序列的和:最优算法
int maxSubSum4(const vector<int> & a)
{
//终于结果
int maxSum = 0;
//当前求和
int nowSum = 0; //遍历序列的全部元素
for (int j = 0; j < a.size(); j++)
{
//将当前元素增加到结果中
nowSum += a[j]; //假设大于最大值,则存储为新的最大值
if(nowSum > maxSum)
maxSum = nowSum;
else if(nowSum < 0)
nowSum = 0;
} return maxSum;
}

这样的算法的时间复杂度为O(N)。

总结

下表是统计的四种算法的运算结果:

输入大小 O(N3) O(N2) O(NlogN) O(N)
N=10 0.000009 0.000004 0.000006 0.000003
N=100 0.002580 0.000109 0.000045 0.000006
N=1000 2.281013 0.010203 0.000485 0.000031
N=10000 NA 1.2329 0.005712 0.000317
N=100000 NA 135 0.064618 0.003206

从表中能够看出,在数据量非常小的时候(在它小时候=.=)。算法在瞬间就完毕了。差距也不是非常明显。
可是随着输入量的增大,一些算法的弊端逐渐显现出来,效率低的甚至在有限的时间里算不出结果来。
对于非常多高效的算法来说,读取数据往往是解决这个问题的瓶颈,

[C++]四种方式求解最大子序列求和问题的更多相关文章

  1. C#批量插入数据到Sqlserver中的四种方式

    我的新书ASP.NET MVC企业级实战预计明年2月份出版,感谢大家关注! 本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的 ...

  2. 【Java EE 学习 80 下】【调用WebService服务的四种方式】【WebService中的注解】

    不考虑第三方框架,如果只使用JDK提供的API,那么可以使用三种方式调用WebService服务:另外还可以使用Ajax调用WebService服务. 预备工作:开启WebService服务,使用jd ...

  3. ASP.NET MVC之下拉框绑定四种方式(十)

    前言 上两节我们讲了文件上传的问题,关于这个上传的问题还未结束,我也在花时间做做分割大文件处理以及显示进度的问题,到时完成的话再发表,为了不耽误学习MVC其他内容的计划,我们今天开始好好讲讲关于MVC ...

  4. SWT组件添加事件的四种方式

    在我们CS日常开发过程中会经常去为组件添加事件,我们常用的为AWT与SWT.SWT的事件模型是和标准的AWT基本一样的.下面将按照事件的四种写法来实现它. 一.匿名内部类的写法 new MouseAd ...

  5. Java实现文件复制的四种方式

    背景:有很多的Java初学者对于文件复制的操作总是搞不懂,下面我将用4中方式实现指定文件的复制. 实现方式一:使用FileInputStream/FileOutputStream字节流进行文件的复制操 ...

  6. C#_批量插入数据到Sqlserver中的四种方式

    先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记 ...

  7. java 20 -10 字节流四种方式复制mp3文件,测试效率

    电脑太渣,好慢..反正速率是: 高效字节流一次读写一个字节数组 > 基本字节流一次读写一个字节数组 > 高效字节流一次读写一个字节 > 基本字节流一次读写一个字节 前两个远远快过后面 ...

  8. .NET MVC控制器向视图传递数据的四种方式

    .NET MVC控制器向视图传递数据的四种方式: 1.ViewBag  ViewBag.Mvc="mvc"; 2.ViewData ViewBag["Mvc"] ...

  9. JavaScript表单提交四种方式

    总结JavaScript表单提交四种方式 <!DOCTYPE html> <html> <head> <title>JavaScript表单提交四种方式 ...

随机推荐

  1. ural 1519 Formula 1

    题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1519 题目分类:插头dp 题意:求经过所有可行点的哈密顿回路的个数  * 不可走 . 可 ...

  2. 开启cocos2dx 3.0的Console功能

    下面内容用于自己知识的备忘,想看具体内容,请參照例如以下地址. 原英文文地址: http://discuss.cocos2d-x.org/t/cocos3-0-tutorial-console-tut ...

  3. Tiny并行计算框架之复杂演示样例

    问题来源  很感谢@doctorwho的问题: 假如职业介绍所来了一批生产汽车的工作,如果生产一辆汽车任务是这种:搭好底盘.拧4个轮胎.安装发动机.安装4个座椅.再装4个车门.最后安装顶棚. 之间有的 ...

  4. 做外贸,独立B2C商城好,还是平台好

    随着跨境电商热的来临,越来越多的国内企业选择进军跨国电商,那么企业要想进军以互联网跨国销售,通常会通过两种途径,一种是建立独立运营的B2C商城,还有一种是依托alibaba,dhgate,aliexp ...

  5. 降低成本是永恒的追求(xamarin)

    减少为主线的成本始终是一个社会经济发展.经济活动似乎很.商业模式的出现相关.我记得早起写Web程序,真正的企业并不多忙.大部分时间处理与浏览器的问题之间的差异所带来. 有些型号也做了屏蔽这样的差别,有 ...

  6. 智能手机的工业控制应用方案——SimpleWiFi在工业控制领域应用

    智能手机的工业控制应用方案——SimpleWiFi在工业控制领域应用    先上图: 现在的智能控制都是基于微控制器,随着智能的手持终端的普及,基于智能终端的控制就会越来越普遍. WIFI便是其中的一 ...

  7. 图像特征提取方法:Bag-of-words

    Bag-of-words简单介绍 最初的Bag-of-words ,也叫做"词袋",在信息检索中,Bag-of-words model假定对于一个文本,忽略其词序和语法,句法,将其 ...

  8. python(abi) RPM DEB Download

    python(abi) RPM DEB Download python(abi) RPM DEB Download

  9. hdu 折线切割平面 (java)

    问题: 仅仅要找到规律问题就攻克了,在做题时应该细致去发现数与数之间的联系. 折线切割平面 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit ...

  10. Java如何检查List<String> 里是否有想要的字符串?

    List<String> test = new ArrayList<String>(); test.add("a"); test.add("b&q ...