最长子数组

问题描述:输入一个整数数组,数组中有正数也有负数,一个或连续的多个整数组成一个子数组,求所有子数组的和的最大值。

求子数组的和的最大值,首先可以求出数组所有子数组的和,再逐一比较可以得到和的最大值。这是最直观易懂的一种解法。但是对一个长度为n的数组,总共有n(n+1)/2个子数组,计算所有子数组的和时间复杂度为O(n^2)。而当n较大时,这种算法是很难被用户接受的。

对于数组(a1, a2, a3, ......, an),设curSum为当前子数组(ai, ai+1, ......, aj)的和,其中1≤i<j<n,令k = j + 1且k ≤ n, sum = 0x80000000表示初始时子数组和的最大值。

1、如果curSum + ak > sum,那么sum = curSum + ak

2、如果curSum + ak ≤ 0,说明curSum已经是子数组(ai, ai+1, ......, aj, ak)的和的最大值, 那么curSum = ak,sum保持不变,对应的子数组为(ai, ai+1, ......, aj)

以数组{-1, -2, 3, 10, -4, 7, -2, -5}为例,初始时sum = 0x80000000, i = 0, curSum = 0

1)i = 0        curSum = -1        sum = -1 

2)i = 1        curSum = -2        sum = -1

3)i = 3        curSum = 3         sum = 3

4)i = 4        curSum = 13       sum = 13

5)i = 5        curSum = 9         sum = 13 

6)i = 6        curSum= 16        sum = 16

7)i = 7        curSum = 11        sum = 16 


#include <iostream>
#include <ctime>
#include <limits>
#include<boost/timer/timer.hpp>
#include<algorithm>
using namespace std;
using namespace boost::timer;
void brute_force_maximum_subarray(int *a,int& index_low,int& index_high,int& maximum,int n)
{
	maximum=numeric_limits<int>::min();	
	for(int i=0;i<n;++i){
		int sum=0;
		for(int j=i;j<n;++j){
			sum+=a[j];
			if(sum>maximum){
				maximum=sum;
				index_low=i;
				index_high=j;
			}			
		}
		//if(a[i]>=maximum){//改进后的暴力法求最大子数组,求出长度为1的最大数
		//	maximum=a[i];
		//	index_low=i;
		//	index_high=i;
		//}
	}	
}

void find_max_cross_subarray(int *a,int& low,int mid,int &high,int &sum)
{
	int index_low=low,index_high=high;
	sum=0;
	int left_sum=numeric_limits<int>::min();	
	int right_sum=numeric_limits<int>::min();
	for(int i=mid;i>=index_low;--i){
		sum+=a[i];
		if(sum>=left_sum){
			left_sum=sum;
			low=i;
		}
	}
	
	sum=0;
	for(int j=mid+1;j<=index_high;++j){
		sum+=a[j];
		if(sum>=right_sum){
			right_sum=sum;
			high=j;
		}
	}
	sum=left_sum+right_sum;
}

void find_maximum_subarray(int *a,int & low,int & high,int &sum)
{
	if(low==high){
		sum=a[low];
	}else{		
		int mid=(low+high)>>1;
		int left_low=low;
		int left_high=mid;
		int left_sum;
		find_maximum_subarray(a,left_low,left_high,left_sum);

		//int mid2=mid+1;
		int right_low=mid+1;
		int right_high=high;
		int right_sum;
		find_maximum_subarray(a,right_low,right_high,right_sum);

		int cross_sum;
		find_max_cross_subarray(a,low,mid,high,cross_sum);

		if(left_sum>right_sum && left_sum>cross_sum){
			low=left_low;
			high=left_high;
			sum=left_sum;
		}else if(right_sum>left_sum && right_sum>cross_sum){
			low=right_low;
			high=right_high;
			sum=right_sum;
		}else{
			sum=cross_sum;
		}
	}
}

void maximum_subarray_liner(int *a,int & low,int & high,int &sum)
{
	int n=high-low+1;
	int ending_here_sum=numeric_limits<int>::min();
	sum=numeric_limits<int>::min();
	int ending_here_low;
	//int ending_here_high;
	for(int i=0;i<n;++i){
		//ending_here_high=i;
		if(ending_here_sum>=0){
			ending_here_sum+=a[i];
		}else{
			ending_here_sum=a[i];
			ending_here_low=i;
		}
		if(ending_here_sum>sum){
			sum=ending_here_sum;
			low=ending_here_low;
			//high=ending_here_high;
			high=i;
		}
	}
}



int main()
{
	//int a[16]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
	int index_low=0,index_high=0,maximum;
	/*violence_maximum_subarray(a,index_low,index_high,maximum,16);
	cout<<index_low<<endl;
	cout<<index_high<<endl;
	cout<<maximum<<endl;*/


	srand(time(NULL));
	int count;
	while ((count=rand()%20)<5);
	count=500000;
	int *b=new int[count];
	//b[0]=0,	b[1]=-4,b[2]=-1,b[3]=-7,b[4]=3;
	for(int i=0;i<count;++i){
		b[i]=rand()%101-50;
		//cout<<b[i]<<" ";
	}
	//cout<<endl;

	cpu_timer t1;
	t1.start();
	brute_force_maximum_subarray(b,index_low,index_high,maximum,count);
	t1.stop();
	cout<<index_low<<endl;
	cout<<index_high<<endl;
	cout<<maximum<<endl;
	cout<<t1.format();
	cout<<endl;

	index_low=0,index_high=count-1,maximum=0;
	cpu_timer t2;
	t2.start();
	find_maximum_subarray(b,index_low,index_high,maximum);
	t2.stop();
	cout<<index_low<<endl;
	cout<<index_high<<endl;
	cout<<maximum<<endl;
	cout<<t2.format();
	cout<<endl;

	index_low=0,index_high=count-1,maximum=0;
	cpu_timer t3;
	t3.start();
	maximum_subarray_liner(b,index_low,index_high,maximum);
	t3.stop();
	cout<<index_low<<endl;
	cout<<index_high<<endl;
	cout<<maximum<<endl;
	cout<<t3.format();
	cout<<endl;

	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值