用分治策略求最大子数组

最大子数组: 有一数组A,求出A的和最大 的子数组,称这个连续子数组称为最大子数组。

因为一个数组可能有多个子数组达到最大和,在这里是只求出一个最大子数组。

如下面的一个数组。



假定我们查找A[low...high]中的最大子数组,使用分治技术我们可以分成两个规模尽量相等的子数组,

也就是说找到子数组的中央; 即:

mid = low + (high - low) / 2;<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
那么最大子数组A[i...j]可能所有三种情况 

1. 完全位于左子数组 A[low...mid] ;  low <=i <=j <= high;

2.完全位于右子数组 A[mid+1...high]   mid<i <=j <=high;

3.跨越中点,因此 low <= i< j <= high.

经过分析, A[low...high]的一个最大子数组所处的位置,必然是上述三种情况之一。

实际上,就是三种情况下,求出的最大的那个。

通过递归求解 A[low...mid], A[]mid+1...high]中的最大子数组,因为这两个子问题仍是最大的子数组问题。

然后再求跨越中点的最大子数组,然后在这再种情况下选取最大值。


首先先完全求出跨越中点的最大子数组。

int find_max_cross_maxsum(int *a, int low, int mid, int high){
	int left_sum = -65535;  //存放一个数组 a 不可能出现的最小值,用于比较。
	int right_sum = -65535;
	int sum = 0;
	int i = 0;
	for(i = mid; i>=low; i--){  
		sum += a[i]; 
		if( sum > left_sum ){
			left_sum = sum;
		}
	}
	sum = 0;
	for(i=mid+1; i<=high; i++){
		sum+=a[i];
		if( sum > right_sum){
			right_sum = sum;
		}
	}

	return left_sum + right_sum;
}	


递归求出最大子数组。

int find_max_subarray(int *a, int low, int high){
	int left_sum, right_sum, cross_sum, mid;

	if(low == high){
		return a[low]; // 递归结束条件。 
	}
	else{
		mid = low + (high-low) / 2;
		left_sum = find_max_subarray(a, low, mid); //求出左子数组最大子数组。 
		right_sum = find_max_subarray(a, mid+1, high);//求出右子数组最大子数组。
		cross_sum = find_max_cross_maxsum(a, low, mid, high); //求出跨越中点的最大子数组
        }
//三种情况,最大的那个就是最大子数组。
	if(left_sum >= right_sum && left_sum >=cross_sum){
		return left_sum;
	}else if(right_sum >=left_sum && right_sum >= cross_sum){
		return right_sum;
	}else{
		return cross_sum;
	}
}

 

测试代码:

int main(){
	int a[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7 , 12, -5, -22 , 15};
	int max_sum = find_max_subarray(a, 0, sizeof(a)/sizeof(a[0]) - 1);
	printf("%d\n", max_sum);
}
结果返回  43, 即 18, 20 ,-7 , 12 这四个连续位置的和,

如果想具体知道是那个下标到那个下标,可以自行修改。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值