最大子序列和问题

问题: 
给定一整数序列A1, A2,... An (可能有负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大 

例如:整数序列-2, 11, -4, 13, -5, 2, -5, -3, 12, -9的最大子序列的和为21。对于这个问题,最简单也是最容易想到的那就是穷举所有子序列的方法。利用三重循环,依次求出所有子序列的和然后取最大的那个。当然算法复杂度会达到O(n^3)。

算法一:

long maxSubSum1( const vector<int> & a )
{
	long maxSum = 0; 
	for (int i = 0; i < a.size(); i++) //i表示子序列起始下标
	{ 
		for (int j = i; j < a.size(); j++) //j表示子序列结束下标
		{ 
			long thisSum = 0; 

			for (int k = i; k <= j; k++) //遍历子序列的开头和结束下标,计算子序列的和
			{ 
				thisSum += a[k]; 
			} 
			if (thisSum > maxSum) //判断最大子序列
				maxSum = thisSum; 
		} 
	} 
	return maxSum; 
}

这个算法很简单,i表示子序列起始下标,j表示子序列结束下标,遍历子序列的开头和结束下标,计算子序列的和,然后判断最大子序列。很明显的看出算法复杂度是O( pow( n, 3 ) )

算法本身很容易理解,而且很直观的感觉在最内层for循环中做了很多无用操作,例如:i = 0, j = 3时,会计算a[0] + a[1] +…+ a[3];而当i = 0, j = 4时候又会计算a[0] + a[1] +…a[4]

算法二:

long maxSubSum2( const vector<int> & a )
{
	long maxSum = 0; 
	for (int i = 0; i < a.size(); i++) //i表示子序列起始下标
	{ 
		long thisSum = 0; 

		for (int j = i; j < a.size(); j++) //j表示子序列结束下标
		{ 
			thisSum += a[j];  
			if (thisSum > maxSum) //thisSum表示a[i] + a[i+1] + … + a[j-1],相比算法1减少最内层的for循环
				maxSum = thisSum; 
		} 
	} 
	return maxSum; 
}
这是一个非常直观的穷举法(比上面的分析还有简单些),而且没有多余重复的操作,复杂度为 O(N^2)   。其中, thisSum 表示 a[i] + a[i+1] + … + a[j-1]

算法三:

分治法:最大子序列和可能出现在三个地方:整个出现在输入数据的左半部分,整个出现在输入数据的右半部分,或者跨越输入数据的中部从而占据左右两个半部分。

代码如下:

long maxSubSum3( const vector<int> & a )//启动函数
{
    return maxSubSum3(a,0,a.size()-1);
}

long maxSubSum3( const vector<int> & a,int left,int right )
{
    
    if(left == right)//只有1个元素了
    {
        if(a[left] > 0)//他就是最大子列
        {
            return a[left];
        }
        else
        {
            return 0;
        }
    }

    else
    {
        //开始分
        int middle = (left + right)/2;
        long maxLeftSum = maxSubSum3(a,left,middle);
        long maxRightSum = maxSubSum3(a,middle+1,right);


        //开始归并了
        //求出前半部分(包含最后1个元素)最大值
        long maxLeftBorderSum = 0, leftBorderSum = 0;
        for(int i = middle; i >= left;i--)
        {
            leftBorderSum += a[i];
            if(leftBorderSum > maxLeftBorderSum)
            {
                maxLeftBorderSum = leftBorderSum;
            }
        }

        //求出后半部分(包含第1个元素)最大值
        long maxRightBorderSum = 0, rightBorderSum = 0;
        for(int i = middle+1; i <= right;i++)
        {
            rightBorderSum += a[i];
            if(rightBorderSum > maxRightBorderSum)
            {
                maxRightBorderSum = rightBorderSum;
            }
        }

        return max(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum);
    }
    
}


int max(int a,int b,int c)
{
    int max = a;
    if(a < b)
    {
        max = b;
    }

    if(b < c)
    {
        max = c;
    }

    return max;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值