最大子数组(分治法)

寻找A[low, high]中的最大连续子数组A[i, j]
 mid=(low+high)/2,欲求的最大连续子数组出现的位置:
   1、出现在A[low, mid]中 ,            即     low<=i<=j<=mid
   2、出现在A[mid+1,high]中,           即    mid<i<=j<=high
   3、跨越了mid位置,出现在A[low, high]中,即      low<=i<=mid<j<=high,        即这个最大连续子数组肯定包含了A[mid]和A[mid+1] 元素!

先来看第三种情况:
   求出包含mid位置的左边最大连续子数组:
   
   
int left_max_sum=-999;
int sum=0;
int left;
for(int i=mid;i>=low;i--){
sum+=a[i];
if(sum>left_max_sum){
left_max_sum=sum;
left=i;
}
}

求出包含mid+1 位置的右边最大连续子数组:

   
   
sum=0;
int right_max_sum=-999;
int right;
for(int j=mid+1;j<=high;j++){
sum+=a[j];
if(sum>right_max_sum){
right_max_sum=sum;
right=j;
}
}
第三种情况的最大连续子数组即是把上面的包含 mid位置的左边最大连续子数组 和包含 mid+1的右边最大连续子数组加起来!

对于第一种 A[i, j] 出现在出现在A[low, mid]中 和第二种A[i, j]出现在A[mid+1,high]中的情况直接用递归了。求出这三种情况下的最大连续子数组,只要找出和最大的连续子数组即可!

   
   
left_right_sum FIND_MAX_SUBBARY(int a[], int low, int high){
if(low==high){
left_right_sum d={low,high,a[low]};
return d;
}
int mid=(low+high)/2;
left_right_sum dl=FIND_MAX_SUBBARY(a,low,mid);
left_right_sum dr=FIND_MAX_SUBBARY(a,mid+1,high);
left_right_sum dm=FIND_MAX_CROSSING_SUBARRAY(a,low,high,mid);
left_right_sum dmax;
if(dl.max_sum>=dr.max_sum&&dl.max_sum>=dm.max_sum){
dmax=dl;
}else if(dr.max_sum>=dl.max_sum&&dr.max_sum>=dm.max_sum){
dmax=dr;
}else{
dmax=dm;
}

上代码:

   
   
#include <iostream>
using namespace std;
#define N 16
struct left_right_sum{
int left;
int right;
int max_sum;
};
left_right_sum FIND_MAX_SUBBARY(int a[], int low, int high);
left_right_sum FIND_MAX_CROSSING_SUBARRAY(int a[], int l, int r, int mid);
int main()
{
// int a[N]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int a[N]={13,-3,-25,-20,-3,-16,-23,-18,-20,-7,-12,-5,-22,-15,-4,-7};
left_right_sum d=FIND_MAX_SUBBARY(a,0,N-1);
cout<<d.left<<" : "<<d.right<<" : "<<d.max_sum<<endl;
}
left_right_sum FIND_MAX_SUBBARY(int a[], int low, int high){
if(low==high){
left_right_sum d={low,high,a[low]};
// left_right_sum *dd=&d;
return d;
}
int mid=(low+high)/2;
left_right_sum dl=FIND_MAX_SUBBARY(a,low,mid);
left_right_sum dr=FIND_MAX_SUBBARY(a,mid+1,high);
left_right_sum dm=FIND_MAX_CROSSING_SUBARRAY(a,low,high,mid);
{
cout<<"low: "<<low<<" right: "<<high<<endl;
cout<<dl.left<<" : "<<dl.right<<" : "<<dl.max_sum<<endl;
cout<<dr.left<<" : "<<dr.right<<" : "<<dr.max_sum<<endl;
cout<<dm.left<<" : "<<dm.right<<" : "<<dm.max_sum<<endl;
}
left_right_sum dmax;
if(dl.max_sum>=dr.max_sum&&dl.max_sum>=dm.max_sum){ //此处等号不能少!!!!!
//return dl;
dmax=dl;
}else if(dr.max_sum>=dl.max_sum&&dr.max_sum>=dm.max_sum){ //此处等号不能少!!!!!
//return dr;
dmax=dr;
}else{
//return dm;
dmax=dm;
}
cout<<dmax.left<<" : "<<dmax.right<<" : "<<dmax.max_sum<<endl;
cout<<"-----------------------------"<<endl;
return dmax;
}
left_right_sum FIND_MAX_CROSSING_SUBARRAY(int a[], int l, int r, int mid){
int left_max_sum=-999;
int sum=0;
int left;
for(int i=mid;i>=l;i--){
sum+=a[i];
if(sum>left_max_sum){
left_max_sum=sum;
left=i;
}
}
sum=0;
int right_max_sum=-999;
int right;
for(int j=mid+1;j<=r;j++){
sum+=a[j];
if(sum>right_max_sum){
right_max_sum=sum;
right=j;
}
}
left_right_sum d1={left,right,left_max_sum+right_max_sum};
// left_right_sum *dd1=&d1;
return d1;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值