目录
分而治之思想:
#1将问题分解为若干简单的子问题
#2通过递归寻求各个子问题的的解
#3合并各个子问题的解,从而得到原始问题的解
最大子序列和问题描述:
给定N个整数的序列{A1,A2,...,AN},求函数f(i,j)=max(0,Ai+...+Aj)的最大值
问题解决思路:
现将序列等分为左右两份,则最大子列只可能出现在三个地方:
1整个子序列出现在左半部分
2整个子序列出现在右半部分
3整个子序列跨越中间边界
前两种情况可以用递归求解,而第三种情况则可以将前半部分的最大子序列和(此处的子序列必须包含前半部分的最后一个元素)与后半部分的最大子序列和(此处的子序列必须包含后半部分的第一个元素)相加得到
注1:因为第三种情况跨越了中间边界,且要求的序列为连续的,因此第三种情况得到的子序列必定包含左子序列的最后一个元素以及右子序列的第一个元素。
注2:若要求的序列可以为不连续的,则第三种情况可以直接用前半部分最大子序列和与后半部分最大子序列和相加得到
问题解决代码:
def findMaxSum(A):
#非常关键,否则会报错“超过最大递归深度”
if len(A)<=1:
return A[0]
mid=len(A)//2
leftA=A[:mid]
rightA=A[mid:]
leftMaxSum=findMaxSum(leftA)#递归求左边的最大序列和
leftAfinal = 0#用于包含左边最后一个数的累加求和
#考虑到存在序列全为负数的情况,因为初始化为负无穷而非0
leftAfinalMax = -float('Inf')#包含左边最后一个数的最大序列和
for i in range(0,len(leftA))[::-1]:
leftAfinal=leftAfinal+leftA[i]
if leftAfinal>leftAfinalMax:
leftAfinalMax=leftAfinal
rightMaxSum=findMaxSum(rightA)#递归求右边的最大序列和
rightAfinal = 0#用于包含右边第一个数的累加求和
#考虑到存在序列全为负数的情况,因为初始化为负无穷而非0
rightAfinalMax = -float('Inf')#包含右边第一个数的最大序列和
for j in range(0,len(rightA)):
rightAfinal=rightAfinal+rightA[j]
if rightAfinal>rightAfinalMax:
rightAfinalMax=rightAfinal
crossMaxSum = leftAfinalMax + rightAfinalMax
return max(leftMaxSum, rightMaxSum, crossMaxSum)
A=[2,3,4,1,-1,7,-3,7,-6]
print(findMaxSum(A))
算法复杂度分析:
令T(N)为求解大小为N的最大子序列和问题所花费的时间,则求解左子序列和右子序列花费的时间分别为T(N/2),在求解第三种情况时,可以看到以上程序中两个for循环次数相加为N,因此两个for循环总共的时间复杂度为O(N)。
综上,以上程序花费的总时间为:
,且
利用上式递归代入有:
直至当N除以k次2时有,此时为递归的终点,此时中括号外会乘以k个2, 即
,一共k个cN,所以有: