比如你获得了一个投资某个股票的机会,并且,你已经准确知道了将来几天这一只股票的相对于前一天的插值,比如为[13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7],那么就有一个问题,从那一天买入,哪一天卖出获益最大?这里就是一个最大字数组问题。
最大字数组问题:在一个数组中找出最大的非空连续子数组
常见方法,暴力求解找出所有的组合,共有C(n,2)种选择,时间复杂度Theta(n^2)
分治法求解最大字数组问题,计算复杂度theta(nlogn)
分治法求解最大字数组的思想是把每一个数组一分为二,每次考虑最大字数组所在的三种可能情况:跨中点,中点左侧,中点右侧。算法的计算量主要在于跨中点这种情况,中点单侧主要是控制划分深度,所以每一层计算复杂度是theta(n),二分以后深度为log(n),因此分治法的计算复杂度是theta(nlogn)
自己写的代码如下
def MaxCrossSubArray(A,low,mid,high):
LeftMaxSum=A[mid]
leftSum=A[mid]
leftIndex=mid
for i in range(mid-1,low-1,-1):
leftSum=leftSum+A[i]
if leftSum>LeftMaxSum:
LeftMaxSum=leftSum
leftIndex=i
rightMaxSum=0
rightSum=0
rightIndex=mid
for i in range(mid+1,high+1):
rightSum+=A[i]
if rightSum>rightMaxSum:
rightMaxSum=rightSum
rightIndex=i
MaxSum=LeftMaxSum+rightMaxSum
return (MaxSum,leftIndex,rightIndex)
def MaxSubArray(A,low,high):
if low==high:
return (A[low],low,high)
mid=(low+high)//2
Left=MaxSubArray(A,low,mid)
Cross=MaxCrossSubArray(A,low,mid,high)
Right=MaxSubArray(A,mid+1,high)
List=[Left,Cross,Right]
result=sorted(List,key = lambda list : list[0],reverse=True)
return result[0]
a=[13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
print(MaxSubArray(a,0,len(a)-1))
代码最后返回一个tuple,tuple包含三个元素,第一个值最大字数组的值,后两个分开始开始索引和终止索引。
这个代码写完,调试成功后,有些地方自己还不是特别明白。在这儿写下来,从新整理一下思路,加深一下对递归的理解。
这个分治想法特别简单,如果不考虑返回最大字数组索引的话特别好理解,就是每一次迭代我都递归寻找单侧最大的,然后与当前跨中点的比较,返回大的。
但是如果我想新加一个返回索引的功能时,可以看到,我的返回索引的地方只有两个,是跨中点的那个函数和递归函数里面递归到字数组只有一个元素的时候。刚开始我的疑惑在于,如果只设置这一个返回索引的地方,是不是有问题呀?我的主要疑惑在于,如果出现连接怎么办,这里是我多想了,因为在每一层的每一个分支,都要运行跨中点的代码,逐层向上的跨中点代码,就是为了包括下层的连接情况。或者说这里的三种情况的划分已经把所有的情况都包括了。
版权声明:本文为博主原创文章,未经博主允许不得转载。