最大子段和问题
最大子段和
问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n 例如,当a[]=(-20,11,-4,13,-5,-2)时,最大子段和为20。
以上内容来自百度百科
思想1:递归思想
分析这个问题,我们可以这么想: 我们把给定的数组搞一条中线出来,设它为mid吧,然后 把它分成两部分,对于这个最大子段和,它有可能出现的地方有多少种情况呢?
- 出现在左边部分,也就是左边的最大子段和大于右边
- 出现在右边部分,和上面相反
- 出现在中间部分,也就是中线被夹在中间
那么,用二分的思想来做,我们是不是可以对左边同样执行上面的步骤,直到只有一个元素了,也就是到达了base case的地步了,这时候我就把这个值返回,然后走右边的。等到两边都走完了,我再看看中间这种情况,然后找出这三者当中大的那个返回给上一级。
我再细讲一下中间情况下是怎么处理的:
既然最大子段和出现再中间位置,那么是不是说,它有一部分数据在中线的左边,一部分数据出现在中线的右边呀?那么,我分别求出中线往左的数的和的最大值,以及中线往右的数的和的最大值,最后把它们加到一起,是不是就是我中间这种情况出现的最大子段和了?
好,那下面上代码看看:
代码
|
|
时间复杂度分析
$T(n)=2T(\frac{n}{2})+2O(n)+O(1)$
由master
公式,$a=2,b=2,d=1\to\log_ba=1=d$ 则时间复杂度:
$$T(n)=O(n*log{n})$$
不知道master
的可以到时间复杂度
这篇博文中进行查看,附上链接:{% post_link 算法基础/时间复杂度 时间复杂度 %}
思想2:动态规划(补充)
在学了动态规划之后,老师还是给我们布置了这一道题,但是它叫最大子序和问题,刚开始我还以为是什么东西,后来想想,发现还是最大子段和问题,只不过现在它换了一种方法做,那就是动态规划。
我们看分治法可以发现,在它求解中间部分的最大子段和问题的时候,他还是用了枚举的这种方法,也就是说,它依然是重复执行了前面遍历过的东西。那我们可以想一种方法,怎么样才能尽可能大的利用我前面走过的数据用于后面的决策?
我们重新想这个问题,我们这个问题是不是相当于求长度为n的序列的最大子序和?
那我们拆分一下这个问题,或者说转换为更加一般的问题求解:
我们求长度为i
的最大子序和,或者说求已知序列前i
个数字的最大子序和。
那我们这样子想,求长度为i
的最大子序和,是不是可以利用前i-1
个长度的序列的最大子序和以及当前位置上的数值a[i]
做出决策?我们设d[i]
表示前i
个长度的序列的最大子序和,那么,像上面说的那样,求d[i]
时可以利用d[i-1]
做出决策,那么d[i]
有如下两种情况:
|
|
这个也很好理解,如果前面的最大子序和为负数了,那$d[i-1]+a[i]<a[i]$,那我还不如那a[i]
作为我当前的最大子序和呢!理解了之后,代码也很简单。
动态规划代码
|
|
时间复杂度:$O(n)$
改进
上面的内容有一个大前提,那就是所给的数组不能全部为负数,但是经过刷题,我发现别人的要求中是没有这一点的,所以,要进行改进,针对全部的数组,都可以返回一个最大子序和。
|
|
题目
洛谷:https://www.luogu.com.cn/problem/P1115
Leetcode: https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/submissions/