最长子数组

来源:互联网 发布:sql 按月分组统计 编辑:程序博客网 时间:2024/06/06 10:54

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

求子数组的和的最大值,首先可以求出数组所有子数组的和,再逐一比较可以得到和的最大值。这是最直观易懂的一种解法。但是对一个长度为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