问题描述
给定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[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。
算法思想
算法一:穷举法
对序列中的所有子段进行遍历求和,通过比较不同子段的和,得到最大的子段和。
算法二:分治法
对于序列{a[i] | i = 1,2,3,…,n},取序列中心为分割点,将序列拆分为left:{a[i] | i = 1,2,…,n/2}和right:{a[i] | i = n/2+1,n/2+2,…,n}。这样最大的子序列将会有三种情况:(1)最大的子序列在left:{a[i] | i = 1,2,…,n/2}中;(2)最大的子序列在right:{a[i] | i = n/2+1,n/2+2,…,n}中;(3)最大的子序列一半在left,一半在right,也就是最大子序列中最少包含元素a[n/2]和a[n/2+1]。
对于这三种情况,只需要分别求解不同情况下的最大子段和,然后三者中最大的值既是整个序列的最大子段和。
算法三:动态规划
运用动态规划解决这个问题,关键的一步就是需要找到状态转移方程。对于序列{a[i] | i = 1,2,3,…,n},maxSum(m) = max{a[1]+a[2]+…+a[m]},即子字段{a[i] | i = 1,2,3,…,m}的最大字段和。由maxSum(m)到maxSum(m+1)的状态转移方程如下:
(1) 如果maxSum(m)>=0,maxSum(m+1)=maxSum(m)+a[m+1]
(2) 如果maxSum(m) < 0,maxSum(m+1)=a[m+1]
对于a[m+1]<0时,得到的maxSum(m+1) < maxSum(m)。所以,需要设置一个变量存储当前的最大字段值。上述的状态转移方程只是一个用于遍历不同子段值的方法。
代码实现
穷举法
# 算法的时间复杂度是O(n^3)
max = 0
for i = 1 to n :
for j = i to n :
sum = 0
for k = i to j :
sum += a[k]
if max < sum :
max = sum
分治法
# 算法的时间复杂度是O(nlogn)
def maxSum(a[], left, right) :
max = 0
if left == right :
if left > 0 :
max = a[left]
else :
max = 0
else :
center = (left + right) / 2
leftMax = maxSum(a, left, center)
rightMax = maxSum(a, center+1, right)
centerSumLeft = 0
leftSum = 0;
for i = center to left :
leftSum += a[i]
if leftSum > centerSumLeft :
centerSumLeft = leftSum
centerSumRight = 0
rightSum = 0
for j = center+1 to right :
rightSum += a[j]
if rightSum > centerSumRight :
centerSumRight = rightSum
centerMax = centerSumLeft + centerSumRight
if leftMax > centerMax :
max = leftMax
else if centerMax > rightMax :
max = centerMax
else :
max = rightMax
return max
动态规划
# 算法的时间复杂度是O(n)
max = 0
sum = 0
for i = 1 to n :
if sum >= 0 :
sum += a[i]
else :
sum = a[i]
if sum > max :
max = sum