编程之美2.14求子数组之和的最大值

本文详细介绍了使用分而治之思想解决最大子数组和问题的方法,包括递归调用和动态规划两种实现方式,并讨论了数组首尾相连时的特殊情况。文章还提供了代码实现和实例分析,帮助读者理解并应用这一经典算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


分而治之的思想(divide and conquer)
#include<iostream>
using namespace std;
int max(int a,int b)
{
	return (a>b)?a:b;
}
int MaxSum(int *A,int low,int high)
{
	//leftMax记录数组左半边最大的值
	//rightMax记录数组右半边最大的值
	int leftMax,rightMax;
	if((high-low)==0)
		return A[low];
	int mid=low+(high-low)/2;
	leftMax=MaxSum(A,low,mid);
	rightMax=MaxSum(A,mid+1,high);
	int lparsum,lmaxparsum,rparsum,rmaxparsum;
	//注意这里初始化为中间的值,若初始化为0
	//则全是负数的数组返回的结果为0
        //而需要返回的结果为这个负数数组中最大的数
         //lmaxparsum记录左半边以A[mid]结尾的最大的子数组和
	//rmaxparsum记录右半边以A[mid+1]开始的最大的子数组和
         lparsum=lmaxparsum=A[mid];
	rparsum=rmaxparsum=A[mid+1];
	for(int i=mid-1;i>=low;i--)
	{
		lparsum+=A[i];
		if(lmaxparsum<lparsum)
			lmaxparsum=lparsum;
	}
	for(int j=mid+2;j<=high;j++)
	{
		rparsum+=A[j];
		if(rmaxparsum<rparsum)
			rmaxparsum=rparsum;
	}
    
	int spanmax=lmaxparsum+rmaxparsum;
	return max(max(leftMax,rightMax),spanmax);

	
}
int main()
{
	int A[6]={1,-2,3,5,-3,2};  
	int B[6]={0,-2,3,5,-1,2};  
	int C[5]={-9,-2,-3,-5,-3};  
	cout<<MaxSum(A,0,5)<<" ";  
	cout<<MaxSum(B,0,5)<<" ";  
	cout<<MaxSum(C,0,4)<<" "<<endl;  
	int i;  
	cin>>i;  
	return 0;  
}
#include<iostream>
using namespace std;

int max(int a,int b)
{

	return (a>b)?a:b;
}
int MaxSum(int *A,int size)
{

	int nStart=A[size-1];
	int nAll=A[size-1];
	int sum=A[size-1];
	for(int i=size-2;i>=0;i--)
	{
		nStart+=A[i];
		nStart=max(A[i],nStart);
		nAll=max(nStart,nAll);

	}
	return nAll;
}

int main()
{

	int A[6]={1,-2,3,5,-3,2};
	int B[6]={0,-2,3,5,-1,2};
	int C[5]={-9,-2,-3,-5,-3};
	cout<<MaxSum(A,6)<<" ";
	cout<<MaxSum(B,6)<<" ";
	cout<<MaxSum(C,5)<<" "<<endl;
	int i;
	cin>>i;
	return 0;



}


动态规划版:

 



扩展问题1

当数组首尾相连时,求子数组之和的最大值

这时需解可能跨越A[0]与A[n-1]的情况,可以分两段计算

以A[0]开始的数组的最大值(A[0],A[1],...A[i])

以A[n]结尾的子数组的最大值(A[j],A[j+1],...A[n-1])

若i<j

则含有A[0]与A[n-1]的最大值为

A[0]+A[1]+...+A[i]+(A[j]+...A[n-1]

若i>j

如数组中无负数

则含有A[0]与A[n-1]的最大值为

整个数组的和

否则需用整个数组的和减去子数组之和的最小值(子数组之和为负)

A[0]+A[1]+..A[n-1]-min(子数组之和)

#include<iostream>
using namespace std;
int max(int x,int y){
	return (x>y)?x:y;
}
int min(int x,int y){
	return (x<=y)?x:y;

}

int MaxSum(int *A,int n){
	//nSpan为数组头尾相连时
	//跨越A[0]与A[n-1]的最大的值
	//还要求出子数组之和为负时的最小值
	int nSpan=0;
	int nStart,nAll;
	//negAll记录子数组之和的最小值
	//negStart记录从数组某个索引开始的最小值
	int negStart,negAll;
	negStart=0;
	negAll=0;
	int temp_sum;
	int Start,All;
	nStart=A[n-1];
	nAll=A[n-1];
	int i;
	int j,k;
	
	int j_index;
	//以A[0]开始的最大的和
	int start_Sum=0;
	int start_Index;
	//以A[n-1]结束的最大的和
	int end_Sum=0;
	int end_Index;
	for(i=n-2;i>=0;i--){
		nStart+=A[i];
		nStart=max(A[i],nStart);
		if(nStart>nAll)
			nAll=nStart;
	}
	start_Sum=A[0];
	start_Index=0;
	temp_sum=start_Sum;
	for(j=1;j<n;j++){
		temp_sum+=A[j];
		if(start_Sum<temp_sum){
			start_Sum=temp_sum;
			start_Index=j;
		}
	}
	end_Sum=A[n-1];
	end_Index=n-1;
	temp_sum=end_Sum;
	for(k=n-2;k>=0;k--){
		temp_sum+=A[k];
		if(end_Sum<temp_sum){
			end_Sum=temp_sum;
			end_Index=k;
		}
	}

	if(start_Index<end_Index){
		nSpan=start_Sum+end_Sum;
		return max(nAll,nSpan);
	}

	else{
		for(i=n-1;i>=0;i--){
			//求出子数组之和最小的值
				negStart=min(A[i],A[i]+negStart);
				negAll=min(negStart,negAll);
		}
		if(negAll<0){
			for(i=0;i<n;i++)
				nSpan+=A[i];
			nSpan-=negAll;
			return nSpan;
		}
		return nAll;
	}
}
int main(){

	int A[]={4,5,6,-7,8,9,10};
	cout<<MaxSum(A,7)<<endl;

	system("pause");
	return 0;
	



}


扩展问题2

只要设置索引变量保存索引即可

#include<iostream>  
using namespace std;  
  

int MaxSum(int *A,int size,int& all_Low,int& all_High)  
{  
	int start_Low;
	int start_High;
    int nStart=A[size-1];  
    int nAll=A[size-1];  
    int sum=A[size-1]; 
	start_High=size-1;
	all_Low=size-1,all_High=size-1;
    for(int i=size-2;i>=0;i--)  
    {  
		start_Low=i;
        nStart+=A[i]; 
		if(A[i]>nStart){
			start_High=i;
			nStart=A[i];
		}
		if(nStart>nAll){
			all_Low=start_Low;
			all_High=start_High;
			nAll=nStart;
		}
       
  
    }  
    return nAll;  
}  
  
int main()  
{  
	int low;
	int high;
	int A[6]={1,-2,3,5,-3,2};  
    int B[6]={0,-2,3,5,-1,2};  
    int C[5]={-9,-2,-3,-5,-3};  
    cout<<MaxSum(A,6,low,high)<<" ";
	cout<<"low="<<low<<" "<<"high="<<high<<endl;
    cout<<MaxSum(B,6,low,high)<<" ";  
	cout<<"low="<<low<<" "<<"high="<<high<<endl;
    cout<<MaxSum(C,5,low,high)<<" "<<endl; 
	cout<<"low="<<low<<" "<<"high="<<high<<endl;
	system("pause");
	return 0;
  
  
}  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值