算法学习-3

求解最大子数组问题

最大子数组问题就是寻找数组A的和最大的非空连续子数组。当然数组A必须包含正负数,如果全是负数或正数则没有意义了,最大子数组显然是数组A本身。

当然我们可以设计一个暴力方法来求解,穷举所以可能的情况。但是这里我们用算法学习2中学过的分治法来求解。但是这个跟归并排序有点不一样,归并排序求解的子问题结果可以直接处理得到原问题的结果,这里并不能通过处理分解后的子问题的解来得到原问题的答案。图a,b很好的说明了原因。

这里写图片描述

我们在A[low,mid]中通过FIND_MAX_SUBARRAY得到最大子问题不一定是A[low,high]的最大子数组,同理在A[mid+1,high]中也一样。但是A[low,high]的最大子数组必然是A[low,mid]的最大子数组,A[mid+1,high]的最大子数组和跨越mid的最大子数组三个中的最大者。如果能求出跨越mid的最大子数组,问题就解决了。

FIND_MAX_CROSSING_SUBARRAY(A,low,high)

    if high > low
        mid = (low + high)/2

        i = 0 //最大子数组的左下标
        Lmax = 0 //跨越mid左边部分最大子数组的和

        j = 0 //最大子数组的右下标
        Rmax = 0 //跨越mid右边部分最大子数组的和

        k = mid
        sum = 0
        while k >= low
            sum = sum + A[k]
            if sum > Lmax
                Lmax = sum
                i = k
            k = k - 1

        k = mid + 1
        sum = 0
        while k <= high
            sum = sum + A[k]
            if sum > Rmax
                Rmax = sum
                j = k
            k = k - 1

        return (i,j,Lmax + Rmax)

结合分解求解,找出最大一组解

//假设函数FIND_MAX_SUBARRAY是一个已经正确实现了查找最大子数组问题这一点对于我们理解把问题拆分求解很有帮助
//返回子数组边界的下标i<=j和sum,(i,j,sum)
FIND_MAX_SUBARRAY(A,low,high)
    if low < high
        mid = low + high/2
        (Li,Lj,Lsum) = FIND_MAX_SUBARRAY(A,low,mid)
        (Ri,Rj,Rsum) = FIND_MAX_SUBARRAY(A,mid+1,high)
        (Ci,Cj,Csum) = FIND_MAX_CROSSING_SUBARRAY(A,low,high)
        //找出最大的和,返回相应的结果
        if max(Lsum,Rsum,Csum) == Lsum
            return (Li,Lj,Lsum)
        else if max(Lsum,Rsum,Csum) == Rsum
            return (Ri,Rj,Rsum)
        else
            return (Ci,Cj,Csum)

下面贴出书本上给出的伪代码,除了表达上有些差别外,逻辑上是一样的

FIND_MAX_CROSSING_SUBARRAY(A,low,mid,high)
    left-sum = -∞
    sum = 0
    for i=mid downto low
        sum = sum + A[i]
        if left-sum < sum
            left-sum = sum
            max-left = i

    right-sum = -∞
    sum = 0
    for j=mid+1 to high
        sum = sum + A[j]
        if right-sum < sum
            right-sum = sum
            max-right = j

    return (max-left,max-right,left-sum + right-sum)

FIND_MAX_SUBARRAY(A,low,high)
    if low == high //数组只有一个元素时,不可拆分,当然结果也是显然的
        return (low,high,A[low])
    else
        mid = (low + high)/2 //结果取整数部分
        (left-low,left-high,left-sum)=FIND_MAX_SUBARRAY(A,low,mid)
        (right-low,right-high,right-sum)=FIND_MAX_SUBARRAY(A,mid+1,high)
        (cross-low,cross-high,cross-sum)=FIND_CROSS_MAX_SUBARRAY(A,low,mid,high)

    if left-sumright-sum and  left-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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值