[算法] 求解和值最大子段及绝对值最小子段

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

 

posted @ 2013-09-04 21:11  ZisZ  阅读(856)  评论(0编辑  收藏  举报