跟:最大子序列问题

特此声明:转载需要说明且附上本人链接!

问题描述

 给定一个无序数组,求其所有子序列的和的最大值。

分析&代码

[方法一]

 很容易想到的解决方法就是穷举法,比较各个子序列的和,最终找到最大值。这种方法很直观,很简单,但会用到多次循环,时间复杂度高,它的思路如下。

 既然是要求子序列的和的最大值,那我就找出所有子序列的和,一个个比较就是了。假设有N个元素,那么我就循环N次,暂称之为1层循环,从0开始一直到N - 1(从第一个元素数到最后一个元素),我们用i来表示1层循环的当前循环index。1层循环的每一次循环都在里面再套一层2层循环,2层循环从i开始到N - 1,我们用j来表示2层循环当前的index,2层循环的序号j每增加一次,就累加一次,之后与最大值进行比较交换 。代码如下图。

方法一

 此算法两层循环,效率并不高,时间复杂度为O(n²)。为什么我们会得到时间复杂度如此low的算法呢?因为我们采用的是最为直观的算法,最容易想到的算法,也是造成重复工作最多的方法,穷举法。我们并没有做深度思考,容易得到的东西往往不是那么好的。下面就让我们做一次深度分析。

[方法二]
 既然方法一是没有经过深度思考得到的可能是效率差的算法,那么我该怎么做深度思考呢?回想一下数轴,从左到右逐渐增大,并以0为分界线,0的左侧为负数,右侧为正数。那么问题来了,一个数字max加上另一个数字num,什么情况下才会变大?那就是只有当num为大于0的数的时候,反之当num小于0的时候就会变小。那么好,我们是不是可以这样,先认定第1个数是最大的数计为max,同时也是当前暂存的大于0的子序列和cur_sum(为什么我们要保存一个大于等于0的和,因为和一旦小于0,谁和它相加都会造成减小的效果,最大子序列一定不是和这个数相加得到的,就应该抛弃。抛弃了我们不怕,因为max中始终保存着计算过的最大值,最大值丢不了),从第2个开始数,直到最后一个。max加上每个数得到的cur_sum相比max都会有三种效果:变小了、不变、变大了。如果变大了,那最大值max就失效,更新max;如果变小了,那么我们就需要判断这个cur_sum是不是小于0了,如果小于了0,最大值一定不会是某个数和这个负数cur_sum之和,那么计和就应该到此为止,最大的子序列要么是之前找到的max,要么就在当前index之后的序列的子序列之中。说的可能不太容易懂,多多回味回味就好啦!代码如下图。
这里写图片描述

 经过一番脑力思考,我们通过 [如果变小了,那么我们就需要判断这个cur_sum是不是小于0了,如果小于了0,最大值一定不会是某个数和这个负数cur_sum之和,那么计和就应该到此为止,最大的子序列要么是之前找到的max,要么就在当前index之后的序列的子序列之中] 的思想成功的避免了遍历过的元素“回头算”的情况,去除了多重循环,将时间复杂度降为了O(n)。

猜你喜欢

转载自blog.csdn.net/maxlovezyy/article/details/60334271
今日推荐