您的位置:首页 > 编程语言 > Python开发

算法导论—分治法计算最大子数组(Python)

2015-06-30 17:47 489 查看
华电北风吹

天津大学认知计算与应用重点实验室

日期:2015/6/30

比如你获得了一个投资某个股票的机会,并且,你已经准确知道了将来几天这一只股票的相对于前一天的插值,比如为[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包含三个元素,第一个值最大字数组的值,后两个分开始开始索引和终止索引。

这个代码写完,调试成功后,有些地方自己还不是特别明白。在这儿写下来,从新整理一下思路,加深一下对递归的理解。

这个分治想法特别简单,如果不考虑返回最大字数组索引的话特别好理解,就是每一次迭代我都递归寻找单侧最大的,然后与当前跨中点的比较,返回大的。

但是如果我想新加一个返回索引的功能时,可以看到,我的返回索引的地方只有两个,是跨中点的那个函数和递归函数里面递归到字数组只有一个元素的时候。刚开始我的疑惑在于,如果只设置这一个返回索引的地方,是不是有问题呀?我的主要疑惑在于,如果出现连接怎么办,这里是我多想了,因为在每一层的每一个分支,都要运行跨中点的代码,逐层向上的跨中点代码,就是为了包括下层的连接情况。或者说这里的三种情况的划分已经把所有的情况都包括了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: