最大连续子序列和问题

给定k个整数的序列{N1,N2,...,Nk },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= k。最大连续子序列是所有连续子序中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{11,-4,13},最大连续子序列和即为20。

注:为方便起见,如果所有整数均为负数,则最大子序列和为0。

解决这样一个问题是一个很有趣的过程,我们可以尝试着从复杂度比较高的算法一步一步地推出复杂度较低的算法。

算法一:

时间复杂度:O(N^3)

其代码:

int MaxSubSequence(const int A[], intN){intThisSum,MaxSum,i,j,k;

MaxSum= 0;for(i=0;i

{for(j=i;j

{

ThisSum= 0;for(k=i;k<=j;k++)

{

ThisSum+=A[k];

}if(ThisSum >MaxSum)

MaxSum=ThisSum;

}

}returnMaxSum;

}

对于此种算法,其主要方法是穷举法,即求出该序列所有子序列的序列和,然后取最大值即可。

算法二:

时间复杂度:O(N^2)

其代码:

int MaxSubSequence(const int A[], intN){intThisSum,MaxSum,i,j;

MaxSum= 0;for(i=0;i

{

ThisSum= 0;for(j=i;j

{

ThisSum+=A[j];if(ThisSum >MaxSum)

MaxSum=ThisSum;

}

}returnMaxSum;

}

对于这种方法,归根究底还是属于穷举法,其间接地求出了所有的连续子序列的和,然后取最大值即可。

那么,这里,我们需要对比一下前面两种算法,为什么同样都是穷举法,但算法一的时间复杂度远高于算法二的时间复杂度?

算法二相较于算法一,其优化主要体现在减少了很多重复的操作。

对于A-B-C-D这样一个序列,

算法一在计算连续子序列和的时候,其过程为:

A-B、A-C、A-D、B-C、B-D、C-D

而对于算法二,其过程为:

A-B、A-C、A-D、B-C、B-D、C-D

其过程貌似是一样的,但是算法一的复杂就在于没有充分利用前面已经求出的子序列和的值。

举个例子,算法一在求A-D连续子序列和的值时,其过程为A-D = A-B + B-C + C-D;

而对于算法二,A-D连续子序列和的求值过程为A-D = A-C+C-D;

这样,算法二充分利用了前面的计算值,这样就大大减少了计算子序列和的步骤。

算法三:递归法(分治法)

时间复杂度:O(NlogN)

易知,对于一数字序列,其最大连续子序列和对应的子序列可能出现在三个地方。或是整个出现在输入数据的前半部(左),或是整个出现在输入数据的后半部(右),或是跨越输入数据的中部从而占据左右两半部分。前两种情况可以通过递归求解,第三种情况可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到,然后将这两个和加在一起即可。

其实现代码为:

int MaxSubSequence(const int A[],intN)

{return MaxSubSum(A,0,N-1);

}static int MaxSubSum(const int A[], int Left, intRight)

{intMaxLeftSum,MaxRightSum;intMaxLeftBorderSum,MaxRightBorderSum;intLeftBorderSum,RightBorderSum;intCenter,i;if(Left ==Right)

{if(A[Left] > 0)returnA[Left];else

return 0;

}

Center= (Left + Right)/2;

MaxLeftSum=MaxSubSequence(A,Left,Center);

MaxRightSum= MaxSubSequence(A,Center+1,Right);

MaxLeftBorderSum= 0;

LeftBorderSum= 0;for(i = Center;i >= Left;i--)

{

LeftBorderSum+=A[i];if(LeftBorderSum >MaxLeftBorderSum)

MaxLeftBorderSum=LeftBorderSum;

}

MaxRightBorderSum= 0;

RightBorderSum= 0;for(i = Center+1;i <= Right;i++)

{

RightBorderSum+=A[i];if(RightBorderSum >MaxRightBorderSum)

MaxRightBorderSum=RightBorderSum;

}return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum +MaxRightBorderSum);

}int Max(int a, int b, intc)

{if(a>b&&a>c)returna;else if(b>a&&b>c)returnb;else

returnc;

}

现在对上面的代码进行相关说明:

Center变量所确定的值将处理序列分割为两部分,一部分为Center前半部,一部分为Center+1后半部。

在上文,我们提到,最大连续子序列的出现位置有三种情况。

对于前两种情况,我们根据递归特性,可以得到:

MaxLeftSum =MaxSubSequence(A,Left,Center);

MaxRightSum= MaxSubSequence(A,Center+1,Right);

而对于第三种情况,我们需要先求出前半部包含最后一个元素的最大子序列:

MaxLeftBorderSum = 0;

LeftBorderSum= 0;for(i = Center;i >= Left;i--)

{

LeftBorderSum+=A[i];if(LeftBorderSum >MaxLeftBorderSum)

MaxLeftBorderSum=LeftBorderSum;

}

然后,再求出后半部包含第一个元素的最大子序列:

MaxRightBorderSum = 0;

RightBorderSum= 0;for(i = Center+1;i <= Right;i++)

{

RightBorderSum+=A[i];if(RightBorderSum >MaxRightBorderSum)

MaxRightBorderSum=RightBorderSum;

}

最后,我们只需比较这三种情况所求出的最大连续子序列和,取最大的一个,即可得到需要求解的答案。

子列和列_最大子列和 - fanlinglong - 博客园相关推荐

  1. webbrowser中localhost和发布的地址_发布一款android版博客园官方app

    1.前言 博客园创立于2004年1月,是一个面向开发者的知识分享社区.自创建以来,博客园一直致力并专注于为开发者打造一个纯净的技术交流社区,推动并帮助开发者通过互联网分享知识,从而让更多开发者从中受益 ...

  2. 阿尔法贝塔阀原理_图总结 - 阿尔法个贝塔 - 博客园

    一.思维导图 二.概念笔记 图的存储结构 1. 邻接矩阵 定义:设图G有n (n大于等于1) 个顶点,则邻接矩阵是一个n阶方阵. 当矩阵中的 [i,j] !=0(下标从1开始) ,代表其对应的第i个顶 ...

  3. java锚点_定位与锚点 - strongerPian - 博客园

    文档流: 普通流:上至下,左至右 浮动流:元素添加了float:: 定位流:添加了定位属性 定位 position:; static 默认值 absolute 绝对定位(脱离文档流,不占位:默认参考浏 ...

  4. 触发器和java的关系_触发器-1 - java ee spring - 博客园

    ------------------------------------环境代码 create  table student (stuid varchar2(10) not null, stuname ...

  5. java费波拉切_面试题 - 不再犯错 - 博客园

    js的基本类型有哪些?引用类型有哪些?null和undefined的区别. 如何判断一个变量是Array类型?如何判断一个变量是Number类型?(都不止一种) Object是引用类型嘛?引用类型和基 ...

  6. python命令行运行模式_[Python] 命令行模式阅读博客园的博文

    1 #-*- coding:UTF-8 -*- 2 importrequests3 from lxml importetree4 importsys5 importio6 importos7 8 9 ...

  7. python拍七游戏代码_拍七数字游戏 - Johannes-Jensen - 博客园

    最近写作业时,老师留了一道关于拍七数字游戏的题,"拍7游戏"规则是:一堆人围成一圈,开始时,任意指定一人说出数字"1"后,一圈人按顺时针方向,每人按整数由小到大 ...

  8. mysql是大端小端_大端和小端 - HackerVirus - 博客园

    在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit.在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过siz ...

  9. java编写某计算器控制台程序_计算器 - 进阶的憨狗 - 博客园

    源起 最近在看程杰著作的<大话设计模式>,全书以小菜和大鸟对话的形势,由浅入深的讲解程序的设计思想,影射出一个个设计模式.我之前虽然也使用过一些设计模式,但没有系统的学习.整理.总结,现从 ...

最新文章

  1. 多线程中堆和栈区别的深入解析
  2. linux ntfs 新建,Linux在NTFS中创建的文件的权限
  3. C语言字符串输出函数puts()的作用是什么
  4. pdf转word python_Python实现PDF转Word
  5. JSON_dump和load
  6. SharePoint Framework 企业向导(三)
  7. 得先好好研究一数据库
  8. 我的世界java出生蘑菇岛,《我的世界》:粉丝强推,出生超巨型蘑菇岛和村庄连在一起...
  9. Android 手势密码解锁 指纹解锁 展示
  10. 242种颜色样式、中英文名称及十六进制的值
  11. 二次开发uniswap-01-SDK
  12. SQL AND OR 运算符的用法
  13. 不同手机型号图文预览_各种手机型号的查询方法(国外英文资料).doc
  14. c++中显示“无法打开xxx.exe进行写入”
  15. java动画迷宫寻路_迷宫寻路算法
  16. 电商客服售前售后话术培训资料合集(共150份)
  17. 计算机准备计划,你为计算机考试做好准备了吗?敬业签便签帮你制定详细复习计划...
  18. 干货|FOF资产配置方案全解析
  19. 【c#】服务端客户端连接类
  20. 配电站房环境监测系统中使用的传感器

热门文章

  1. Sql Server系列:排序函数
  2. Silverlight toolkit 中ListPicker控件的用法【转】
  3. 【C#每日一帖】【转】提高编码效率的一些经验
  4. 惠普收购Palm意在遏制同系竞争
  5. bcp入库oracle,Sybase中的BCP用法实践 与 Oracle的SQLLDR用法实践
  6. 占用率_有问有答:任务管理器里面的GPU占用率到底是怎么算的?
  7. ps分辨率像素英寸和厘米的区别_PS萌新必知的专业术语
  8. java 月度相减_java根据日期获取月龄,按照减法原理,先day相减,不够向month借;然后month相减,不够向year借;最后year相减。...
  9. 剑指offer面试题[8]-旋转数组的最小数字
  10. C++栈与队列基本操作