求和值最大子段:不断对已有子段加值,当和值小于0时舍弃子段;由遍历决定复杂度O(n);
求和值绝对值最小子段:求前n子段和值,然后求最小差值;求最小差值时使用了排序后遍历的方法,由排序决定复杂度O(nlogn);这里求最小差值的问题中,在某些限制条件下(数组波动不大)可以用桶排序进一步降低时间复杂度,见求最小差值,但因有条件限制不稳定,故不选取;
# -*- coding: utf-8 -*-
array = (4, -3, 2, 5, -9, 6)
#array = (4, -3, 1)
#array = (-4, -3, -2, -5, -9, -6)
# 求解和值最大子段
# 算法关键是将和值对整体不利的子序列舍弃,修减问题树
# 复杂度O(n)
def big_sub():
try_sum = 0
try_start = 0
start = 0
end = 0
sum = 0
big = array[0]
big_index = 0
for i in range(0, len(array)):
if try_sum >= 0:
try_sum += array[i]
if (try_sum > sum):
sum = try_sum
end = i
start = try_start
else: # try_sum < 0
try_sum = array[i]
try_start = i
if array[i] > big:
big = array[i]
big_index = i
if sum == 0:
sum = big
start = end = big_index
print array[start:end+1],
print sum
# 求解和值绝对值最小子段
# 算法关键是求解前n子段和后进行排序,找数列最小差值
# 因为有排序过程存在,所以时间复杂度达到O(nlogn)
# 快排
def split(tuples, start, end):
middle = tuples[end]
index = start-1
for i in range(start, end+1):
if tuples[i][1] <= middle[1]:
index += 1
temp = tuples[index]
tuples[index] = tuples[i]
tuples[i] = temp
return index
def sort_tuples(tuples, start, end):
if start < end:
index = split(tuples, start, end)
sort_tuples(tuples, start, index-1)
sort_tuples(tuples, index+1, end)
def small_sub():
sum = 0
sums = []
for i in range(0, len(array)):
sum += array[i]
sums.append((i, sum))
# 排序
sort_tuples(sums, 0, len(sums)-1)
# 找最小差值
small_diff = -1
small_diff_index = 0
for i in range(0, len(array)-1):
diff = sums[i+1][1] - sums[i][1]
if (small_diff < 0) or (diff < small_diff):
small_diff = diff
small_diff_index = i
if (sums[small_diff_index][0] < sums[small_diff_index+1][0]):
start = sums[small_diff_index][0]
end = sums[small_diff_index+1][0]
minus = False
else:
end = sums[small_diff_index][0]
start = sums[small_diff_index+1][0]
minus = True
print array[start+1:end+1],
if minus:
print -small_diff
else:
print small_diff
if __name__ == "__main__":
big_sub()
small_sub()
注:为处理全负数组,在求最大和子段时,用了一个空间big保存最大元素值;