分治法-最大子数组

最大连续子数组

题目描述

           给定一个数组序列(如果数组全部是正数,最大子数组就是序列本身,所以这里假定序列中存在正数跟负数),找到数组中和最大的连续数组。

算法分析

         从题目的描述中我们很容易想到的就是暴力破解,利用两层循环找出最大连续子数组,但是这样的算法复杂度是O(n^2)。这里考虑使用分治法的思想分析问题,找到时间复杂度更小的解决方法。

采用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组,也就是说找到子数组的中央位置,然后考虑求解两个子数组A[low,mid]和A[mid+1,high]。这里只要分为三种情况。

         1、完全位于子数组A[low,mid]中,因此low<=i<=j<=mid。

 2、完全位于子数组A[mid+1,high]中,因此mid<=i<=j<=high。

 3、跨越了中点,因此low<=i<=mid<=j<=high。

跨越中点算法实现

 C语言实现代码
typedef struct Index{
	int indexL,indexR,sum;
}index;
index *cross_subarray(int *A,int low,int mid,int high){
	int sumL=-10000,sumR=-10000,sum=0,i,j,indexL,indexR;
	index *idx;
	for(i=mid;i>=low;i--){
		sum+=A[i];
		if(sum>sumL){
			sumL=sum;
			indexL=i;
		}
	}
	sum=0;
	for(j=mid+1;j<=high;j++){
		sum+=A[j];
		if(sum>sumR){
			sumR=sum;
			indexR=j;
		}
	}
	idx->indexL=indexL;
	idx->indexR=indexR;
	idx->sum=sumR+sumL;
	return idx;
}
Java实现代码
	public static index cross_sub(int A[],int low,int mid,int high){
		index idx = new index();
		int sumL=-10000,sumR=-10000,indexL=low,indexR=high,sum=0,i;
		for(i=mid;i>=low;i--){
			sum=sum+A[i];
			if(sum>sumL){
				sumL=sum;
				indexL=i;
			}
		}
		sum=0;
		for(i=mid+1;i<=high;i++){
			sum=sum+A[i];
			if(sum>sumR){
				sumR=sum;
				indexR=i;
			}
		}
		idx.setLeft(indexL);
		idx.setRight(indexR);
		idx.setSum(sumR+sumL);
		return idx;
	}

分治法完整代码实现

C语言
#include"stdio.h"
typedef struct Index{
	int indexL;
	int indexR;
	int sum;
}index;
index *cross_subarray(int *A,int low,int mid,int high){
	int sumL=-10000,sumR=-10000,sum=0,i,j,indexL,indexR;
	index idx={0,0,0};
	for(i=mid;i>=low;i--){
		sum+=A[i];
		if(sum>sumL){
			sumL=sum;
			indexL=i;
		}
	}
	sum=0;
	for(j=mid+1;j<=high;j++){
		sum+=A[j];
		if(sum>sumR){
			sumR=sum;
			indexR=j;
		}
	}
	idx.indexL=indexL;
	idx.indexR=indexR;
	idx.sum=sumR+sumL;
	return &idx;
}
index *find_subarray(int *A,int low,int high){
	int mid;
	index *idx1,*idx2,*idx3;
	index idx4={0,0,0};
	if(low == high){
		idx4.indexL=low;
		idx4.indexR=high;
		idx4.sum=A[low];
		return &idx4;
	}else{
		mid=(low+high)/2;
		idx1=find_subarray(A,low,mid);
		idx2=find_subarray(A,mid+1,high);
		idx3=cross_subarray(A,low,mid,high);
		if(idx1->sum>=idx2->sum && idx1->sum>=idx3->sum){
			return idx1;
		}else if(idx2->sum>=idx1->sum && idx2->sum>=idx3->sum){
			return idx2;
		}else{
			return idx3;
		}
	}
}
int main(){
	index *idx;
	int A[]={-9,8,-7,6,3,-2,1};
	idx = find_subarray(A,0,6);
	printf("%d,%d,%d\n",idx->indexL,idx->indexR,idx->sum);
	return 0;
}
Java代码实现
public class cross_subarray {

	public static index cross_sub(int A[],int low,int mid,int high){
		index idx = new index();
		int sumL=-10000,sumR=-10000,indexL=low,indexR=high,sum=0,i;
		for(i=mid;i>=low;i--){
			sum=sum+A[i];
			if(sum>sumL){
				sumL=sum;
				indexL=i;
			}
		}
		sum=0;
		for(i=mid+1;i<=high;i++){
			sum=sum+A[i];
			if(sum>sumR){
				sumR=sum;
				indexR=i;
			}
		}
		idx.setLeft(indexL);
		idx.setRight(indexR);
		idx.setSum(sumR+sumL);
		return idx;
	}
	public static index find_subarray(int A[],int low,int high){
		index idx = new index(),
			  idx1 = new index(),
			  idx2 = new index(),
			  idx3 = new index();
		if(low == high){
			idx.setLeft(low);
			idx.setRight(high);
			idx.setSum(A[low]);
			return idx;
		}else{
			int mid = (low+high)/2;
			idx1 = find_subarray(A,low,mid);
			idx2 = find_subarray(A,mid+1,high);
			idx3 = cross_sub(A,low,mid,high);
			if(idx1.getSum()>=idx2.getSum() && idx1.getSum()>=idx3.getSum()){
				return idx1;
			}else if(idx2.getSum()>=idx1.getSum() && idx2.getSum()>=idx3.getSum()){
				return idx2;
			}else{
				return idx3;
			}
		}
	}
	public static void main(String[] args){
		int A[]={-9,8,-7,6,3,-2,1};
		index idx = find_subarray(A,0,6);
		System.out.println(idx.left+","+idx.right+","+idx.sum);
	}
}

算法时间复杂度分析

利用递归式分析算法的时间复杂度:
首先,求跨越中点算法的时间复杂度两个for循环O(n),利用递归拆分数组的算法时间复杂度为O(nlg(n))。所以时间复杂度为(O(n)+O(nlg(n)))。

算法空间复杂度

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值