算法导论——分治策略——最大子数组问题

最大子数组:一个数组A的和最大的非空连续子数组
注意:只有当数组中包含负数时,最大子数组问题才有意义。
暴力求解法:(对每个子数组求和,选出和最大的子数组)
分治策略求解方法:
将数组分成规模尽可能相等的子数组,即找到中间位置,然后考虑左子数组和右子数组,最大子数组位置必然有以下三种情况:

  1. 完全位于左子数组中
  2. 跨过了中点
  3. 完全位于右子数组中
    分别求出三种情况下的最大子数组,再选出三者中最大的子数组即为所求最大子数组。求最大左子树组和最大右子树组同样也是最大子数组问题,只是规模减半,因此可以递归求解。只需另外寻找跨过中点的最大子数组即可。
    可以在线性时间内求出跨越中点的最大子数组:
def find_maxcrossing_subarray(A, low, mid, high):
    '''将跨越中点的子数组依mid分成左、右两个部分,分别向左、右两边扩张求解最大值再相加,即为跨中点最大子数组。
    注意:跨中点,即mid两边至少各有一个元素,否则不跨中点!'''  
    INF=9999999
    left_SUM=-INF #左子数组和初始化为负无穷大,等会循环至少能加进来一个元素
    SUM=0
    min_left=mid #需要提前声明,弱无此条语句,无法返回循环内的局部变量值
    for i in range(mid,low,-1):
        SUM=SUM+A[i] #向左扩展一个元素
        if SUM>left_SUM: #如果扩展后的和比当前左子数组和大,则更新,否则保持
            left_SUM=SUM
            min_left=i #标记左下标
    #右子数组最大值求解和左子数组完全对称
    right_SUM=-INF
    SUM=0
    max_right=mid+1
    for j in range(mid+1,high):
        SUM=SUM+A[j]
        if SUM>right_SUM:
            right_SUM=SUM
            max_right=j
    return(min_left,max_right,left_SUM+right_SUM)

然后就可以编写分治策略的代码:

def find_maximum_subarray(A,low,high):
	if high==low:	
		return(low, high, A[low])	#基础情况:只有一个元素,返回元素值
	else:
		mid=(low+high)//2 #分,递归求解左右子数组最大子数组
		(left_low,left_high,left_sum)=find_maximum_subarray(A,low,mid)
		(right_low,right_high,right_sum)=find_maximum_subarray(A,mid+1,high)
		#调用之前编写的求跨过中点最大子数组函数
		(cross_low,cross_high,cross_sum)=find_maxcrossing_subarray(A,low,mid,high)
		#比较大小,返回三者中和最大的子数组
		if left_sum>=right_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)

作为算法导论中第一个实例问题,最大子数组问题理解起来非常容易。这也和符合分治策略的特点,用起来简单,但是分析复杂度比较困难,原因在于分治的特点是递归。所以学习的重点不应该局限于运用分治算法,还应掌握其算法分析。

书上的样例测试:
数组需要定义为:
A=[0,13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
low=0,high=len(A)-1
直接print可得:
返回一个三元组,分别代表最大子数组的起始下标终点下标以及最大子数组的和

注:此系列为作者学习算法导论是记录的笔记,详情请阅读原书第四章,分治策略。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值