最大子序列和问题的解

前言:此问题是著名的《数据结构与算法分析》第二章算法导论的第一个例子,用来阐释算法性能有优劣之分。当输入量的规模在很小的量级,只要问题能得到解决便已达到目的,伴随解决问题所花费的时间空间显得微乎其微。而当输入量的规模极其庞大,成百上千万时,算法性能的好坏便显得尤为重要,在问题解决的同时,坏算法花费几个月几年的时间,并且花费了电脑所有的内存,好算法在几秒内解决问题。这就是算法性能优劣的重要性的体现。在下面的例子中举出四种解法,所花费的时间由长到短,可以直观的展示好坏算法的优劣之处。

问题描述:给定整数A1,A2,...,AN(可能有负数),求的最大值(为方便期间,如果所有整数均为负数,则最大子序列和为0)。

例:输入-2,11,-4,13,-5,-2,答案为20(从A2到A4)。


解法1:枚举法O(n3)

当没有思路时,逻辑最简单也是最花时间的方法就是枚举法。解体关键是“最大”和“子序列”,“最大”意味着列举所有的序列情况依次和人为设置的MaxSum比较,比它大则将值赋给MaxSum,最终得到的MaxSum就是所有情况中最大的。“子序列”是给定数组中x个连续的数组成的序列,x取值范围从1到N。解法一,使用了三层for循环来枚举,则时间复杂度为O(n3),i,j为子序列的左右界,ThisSum是当前子序列的和。ThisSum=A[i]+...+A[j]。k是为了从i加到j的一个局部变量。


解法二:枚举法改良版O(n2)


枚举法简单在于解题者不用多想以最粗暴的方法解题,而花时间在于进行了大量的重复计算,因此不是一个优秀的算法。我们发现解法一中的第三层循环可以不要,每确定一组i,j(i<=j)都要通过for循环计算子序列的和。我们改进为 ,这样就能省略一个for循环来降低时间复杂度。


解法三:枚举法终极版O(n)


由于子序列的左右界 i,j是不固定的,在解法一中,使用双层for循环枚举所有 i,j情况,每种情况的 i,j又使用for循环来计算子序列和,一共用了三层循环。在解法二中,用了for循环枚举子序列左界 i的情况,又使用一层for循环列举 j的所有情况下的最大序列和。而解法三中,只使用了一次for循环遍历了N个元素,设置ThisSum表示当前的子序列和,每经历一个元素便加进ThisSum,更新后的ThisSum与MaxSum比较,比他大则赋值,否则,如果比 0 小,则将ThisSum=0。本算法有许多好处:①时间复杂度只有O(n),基本上是最省时的算法。②它只对数据进行一次扫描,一旦A[i]被读入并被处理,它就不再需要被记忆。因此,如果数组在磁盘或磁带上,它就可以被顺序读入,在主存中不必存储数组的任何部分。③在任意时刻,算法都能对它已经读入的数据给出子序列问题的正确答案,称为联机算法。


解法四:递推分治算法O(nlog(n))

解法四使用了一种和前三种都不一样的思想,也是算法分析中常用的两种思想“递推”和“分治”。对于N个元素的数组,将其分为两部分,则最大子序列和则是左部分的最大子序列和MaxLeftSum,右部分最大子序列和MaxRightSum,包含中间元素的最大子序列和MaxLeftBorderSum+MaxRightBorderSum,这三类中的最大值。6-7行计算左右两部分的最大子序列和,利用递推的方法。8-17行计算包含中间元素的最大子序列和,使用了两个for循环时间单位为O(n)。最终,时间复杂度为O(nlog(n))。对于带log的时间复杂度的分析,《数据结构与算法分析》这本书后面又举了三个例子来说明,后面一篇文章会进行阐述。


结语:作者在本题解法结尾说了一句话:“仅需要常量空间并以限行时间运行的在线算法几乎是完美的算法”,就是解法三。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值