最大子数组问题描述:寻找数组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.算法导论 机械工业出版社 第四章第一节 最大子数组问题。