算法导论——python实践(4.1最大子数组问题)

最大子数组问题描述:寻找数组A的和最大非空连续子数组

4.1.1暴力求解

简单的尝试对每对可能存在的子数组的和进行计算,长度为n的数组总共有n*(n+1)/2中可能


#  最大子数组问题暴力求解
def find_key(dict):
    new_keylist=[]
    b=max(dict,key=dict.get)#找出dict中的值最大值所对应的关键字(这里表示最大子数组)
    print (dict[b])
    for key in dict:
        if dict[key]==dict[b]:
            new_keylist.append(key)#可能存在多个最大子数组的情况
    return new_keylist

a=[100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97]#原始数据
b=[]
for i in range(1,len(a)):
    b.append(a[i]-a[i-1])  #增量数组
print (b)
new=[]
d={}
for i in range(0,len(b)):   #子数组长度为i
    for j in range(0,len(b)-i):
        key=sum(b[j:1+j+i])
        new=tuple(b[j:1+j+i])
        d[new]=key
v=list(d.values())
print (d)
print (find_key(d))

具体思路是:将算出和的数组作为字典d的关键字,算出的和作为d的相对应的关键字的和,在find_key函数中, b=max(dict,key=dict.get)是为了找出dict中的值最大值所对应的关键字(这里表示最大子数组),由于可能存在多个最大子数组的情况,这里可以将其都打印出来。

4.1.2使用分治策略的求解方法

分治解法详解

find_max_crossing函数是求解跨越重点的最大子数组,返回一个下标元组划定跨越中点的最大子数组的边界,并返回最大子数组的值的和,find_max_subarray是递归函数,对于每个分解后的数组,其最大子数组问题都只有三种可能:完全位于数组A的左半边,完全位于数组A的右半边,跨越了中点,因此可使用分治策略,对每个递归的数组,求解三种情况下的最大子数组,并进行比较和的大小,从而确定最大子数组的上下标的边界。递归终止条件:当分解后的数组中只有一个元素时,该数组的最大子数组就是其本身。

#  最大子数组问题
import math
def find_max_crossing(seq,low,mid,high):
    left_sum = float("-inf")#定义个无穷小的数值
    sum=0
    for i in range(mid,low-1,-1):
        sum=seq[i]+sum
        if sum>left_sum:
            left_sum=sum
            max_left=i
    sum=0
    right_sum=float('-inf')
    for j in range(mid+1,high+1):
        sum=seq[j]+sum
        if sum>right_sum:
            right_sum=sum
            max_right=j
    return [max_left,max_right,left_sum+right_sum]


def find_max_subarray(seq,low,high):

    if high==low:#递归终止条件
        return[low,high,float(seq[low])]
    else:
        mid=((low+high)//2)

        [left_low,left_high,left_sum]=find_max_subarray(seq,low,mid)

        [right_low,right_high,right_sum]=find_max_subarray(seq,mid+1,high)

        [cross_low,cross_high,cross_sum]=find_max_crossing(seq,low,mid,high)


        if (left_sum>=right_sum)and(right_sum>=cross_sum):
            return [left_low,left_high,left_sum]
        elif (right_sum>=left_sum)and(right_sum>=cross_sum):
            return [right_low,right_high,right_sum]
        else:
            return [cross_low,cross_high,cross_sum]
a=[100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97]#原始数据
b=[]
for i in range(1,len(a)):
    b.append(a[i]-a[i-1])  #增量数组
print (b)
print(find_max_subarray(b,0,len(b)-1))

参考文献:

1.算法导论 机械工业出版社 第四章第一节 最大子数组问题。

猜你喜欢

转载自blog.csdn.net/weixin_42206504/article/details/81290556