求数组的子数组之和最大值

题目:一个有N个整数元素的一维数组A[0...n-1]这个数组当然有很多子数组,那么子数组之和最大值是多少?

解答:求子数组之和最大,这里是连续的子数组,如果一个数为负数,数组之和会减少,记住最大值,只要数组之和没有小于0就可以继续累加,比如{-2,3,-1,9},3到-1子数组之和减小了,但是没有小于0,可以继续累加下一个数9,就可以得到最大和3-1+9。如果子数组之和小于0了,必须重新开始累加。

int Max_array(int *a,int n)
{
	if(a==NULL||n<=0)
	{
		cout<<"error";
		return 0;
	}
	int sum=0,max=a[0];
	for(int i=0;i<n;i++)
	{
		sum+=a[i];
		if(max<sum)
			max=sum;
		if(sum<0)
			sum=0;
	}
	return max;
}
以上程序时间复杂度为O(N),只遍历了数组一遍。

拓展:

1.如果数组A[0..n-1]首位相连,也就是允许找到一段数字(A[i]...A[n-1],A[0]...A[j]),使其和最大,怎么办?

解答:分两种情况讨论:

(1)不跨越A[n-1],A[0],就是上题的解法;

(2)跨越A[n-1],A[0]。

对于(2)跨越A[n-1],A[0]其实就是从某个位置i开始到n-1,在从0开始到j,即A[i]...A[n-1]A[0]...A[j],可以求从某个位置到结尾的最大值,和从开头到某个位置的最大值。

int Max_array(int *a,int n)
{
	if(a==NULL||n<=0)
	{
		cout<<"error";
		return 0;
	}
	int sum=0,max=a[0];
	for(int i=0;i<n;i++)
	{
		sum+=a[i];
		if(max<sum)
			max=sum;
		if(sum<0)
			sum=0;
	}
	return max;
}

int Max_contain(int *a,int n)
{
	if(a==NULL||n<=0)
	{
		cout<<"error";
		return 0;
	}
	int max1=a[0];
	int max2=a[n-1];
	int sum=0;
	for(int i=0;i<n;i++)
	{
		sum+=a[i];
		if(sum>max1)
			max1=sum;
		if(sum<=0)
			break;
	}
	sum=0;
	for(int j=n-1;j>i;j--)
	{
		sum+=a[j];
		if(sum>max2)
			max2=sum;
		if(sum<=0)
			break;
	}
	return max1+max2;
}


int main()
{
	int a[]={3,2,-6,1,-3,6,7};
	cout<<(Max_array(a,7)>Max_contain(a,7)?Max_array(a,7):Max_contain(a,7))<<endl;
	return 0;
}
		
2.如果题目要求同时返回最大子数组的位置,算法该如何改变,还能保证O(N)时间复杂度?

解答:可以设置连个变量保存开始位置和结束位置,只有当max<sum时,才需要调整结束位置;只有当sum<0时可能需要调整开始位置,先记录这个位置。

int Max_array(int *a,int n,int &start,int &end)
{
	if(a==NULL||n<=0)
	{
		cout<<"error";
		return 0;
	}
	start=end=0;
	int left=0;
	int sum=0,max=a[0];
	for(int i=0;i<n;i++)
	{
		sum+=a[i];
		if(max<sum)
		{
			max=sum;
			start=left;
			end=i;
		}
		if(sum<0)
		{
			sum=0;
			left=i+1;
		}
	}
	return max;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值