问题描述:
给定一个由数字组成的数组,求出和最大的子数组
求解方法:
1.暴力法
选取所有连续和的可能性
#最大连续子序列,暴力法
l=[2,3,-9,3,2,1,-1,5,-9,1,2,3]
lo=0
hi=len(l) - 1
m=l[0]
for i in range(lo,hi+1):
for j in range(i,hi+1):
cursum=0
for k in (i,j):
cursum+=l[k]
m=max(m,cursum)
print(m)
由于i,j,k的范围都是[0,n],则时间复杂度为O()
2.暴力优化
利用数组sum储存0-i项和,两次遍历sum数组得到连续和
#最大连续子序列,暴力法优化
l=[0,2,3,-9,3,2,1,-1,5,-9,1,2,3]#数组第一项为零防止越界
lo=1
hi=len(l) - 1
sum=[0]*len(l)
m = l[1]
for i in range(lo,hi+1):
sum[i]=sum[i-1]+l[i]
for i in range(lo,hi+1):
for j in range(i,hi+1):
cursum = sum[j] - sum[i-1]#求i到j之间的连续和
m = max(cursum,m)
print(m)
由于sum数组的长度为n 所以时间复杂度为O()
利用i,j来控制子数组的首尾项
#最大连续子序列,暴力法优化
l=[2,3,-9,3,2,1,-1,5,-9,1,2,3]
lo=1
hi=len(l) - 1
m = l[1]
#i为子序列首项,j为尾项
for i in range(lo,hi+1):
sum = 0
for j in range(i,hi+1):
sum += l[j]
m = max(m,sum)
print(m)
3.分治法
将问题分为两个子问题
1.最大子序列全部出现在左边或右边则递归解决
2.最大子序列横跨中点,将左半部分最大的连续和加上右半部分最大连续和相加即为最大连续和
#最大连续子序列,分治法
l=[1,-9,4,7,-1,2]
lo=0
hi=len(l)-1
def f(l,lo,hi):
if lo==hi:
return l[lo];
mid = (hi-lo)//2 + lo
m1 = f(l,lo,mid)
m2 = f(l,mid+1,hi)
left=l[mid]
right=l[mid+1]
now=0
for i in range(mid,lo-1,-1):
now+=l[i]
left=max(now,left)
now=0
for i in range(mid+1,hi+1):
now+=l[i]
right=max(now,right)
m3=left+right;
return max(m1,m2,m3);
print(f(l,lo,hi))
4.分析法
因为最大 连续子序列和只可能是以位置0~n-1中某个位置结尾。当遍历到第i个元素时,判断在它前面的连续子序列和是否大于0,如果大于0,则以位置i结尾的最大连续子序列和为元素i和前门的连续子序列和相加;否则,则以位置i结尾的最大连续子序列和为元素i。
#最大连续子序列,分析法
l=[2,3,-9,3,2,1,-1,5,-9,1,2,3]
lo=0
hi=len(l) - 1
maxhere=maxsum= 0
for i in range(lo,hi+1):
if maxhere<=0 :
maxhere = l[i]
else:
maxhere+=l[i]
maxsum=max(maxhere,maxsum)
print(maxsum)
时间复杂度O(n)
5.动态规划
记s[i]是以a[i]结尾的最大子数组和
s[i+1]=max(s[i]+a[i+1],a[i+1])
s[0]=a[0];
遍历数组a[i]即可得到以每一项结尾的最大子数组和s[i],求出其中最大值
#最大连续子序列,动态规划
l=[2,3,-9,3,2,1,-1,5,-9,1,2,3]
lo=1
hi=len(l) - 1
s=[0]*len(l)#初始化字符串
s[0]=l[0]
for i in range(lo,hi+1):
s[i]=s[i-1]+l[i]
s[i]=max(s[i],l[i])
print(max(s))