[算法] 求解和值最大子段及绝对值最小子段
求和值最大子段:不断对已有子段加值,当和值小于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保存最大元素值;