《剑指offer》:[31]连续子数组的最大和及子序列的值

题目:输入一个整形数组,数组里有整数也有负数。数组中一个或连续多个整数组成一个子数组。求所有子数组的和的最大值和其序列的值。要求时间复杂度为O(N)。例如输入数组为{1,-2,3,10,-4,7,2,5},最后输出的最大该子数组的和为18。
方案一:最直观的方法就是列举出数组中所有的子数列,然后对应的每个子数列进行求和。最后再找出最大的一个。对于n个元素的数组,有n(n+1)/2 个子数列。
最快的时间复杂度为:O(N*N)。

方案二:O(N)时间复杂度的算法。根据数组找出相应的规律,减少相应的计算量。以上面的数组为例,具体分析如下:


方案三:利用动态规划的方法。用函数f(i)表示以第i个数字结尾的子数组的最大和,而我们需要求出max[f(i)],其中0<=i<=n。我们可以用如下递归公式求f(i)。
如果i=0,就是第一项;如果f(i-1)<=0,那么就将舍弃前面的子数列,因为加起来会使后面的自数列的值<=自身子数列的值,所以舍弃。

如果i不等于0,且f(i-1)>0,那么它会使后面的自数列的值>自身子数列的值,所以保留。

用公式表示如下:


方案二与方案三的思想虽有区别,但是异曲同工。其具体实现代码如下:
#include <iostream>
using namespace std;
int arr[8]={1,-2,3,10,-4,7,2,-5};
bool IsInvalidInput=false;
int FindGreatestSumOfSubArray(int *array,int length)
{
	if(NULL==array || length<=0)
	{
		IsInvalidInput=true;
		return 0;
	}
	IsInvalidInput=false;
	int CurSum=0;
	int nGreatestSum=array[0];
	for(int i=0;i<length;i++)
	{
		if(CurSum<=0)
			CurSum=array[i];
		else
			CurSum+=array[i];
		if(CurSum>nGreatestSum)
			nGreatestSum=CurSum;
	}
	return nGreatestSum;
}
int main()
{
	int Greatest=FindGreatestSumOfSubArray(arr,8);
	if(!IsInvalidInput)//用这个全局变量来标记输入是否有效是必要的,因为函数的返回值有可能返回0,那么我们要利用这个标志来判断是程序正常的返回0,还是输入无效返回0;
		cout<<"Greastest: "<<Greatest<<endl;
	else
		cout<<"THE INPUT IS INVALID!"<<endl;
	system("pause");
	return 0;
}

运行结果:


知道了最大子序列的和,有时候我们还要知道最大子序列和的序列值。我们用一个容器保存其值就可以了,其实现代码如下:

#include <iostream>
using namespace std;
#include <deque>
int arr[8]={1,-2,3,10,-4,7,2,-5};
bool IsInvalidInput=false;
deque<int> de;
deque<int>::iterator it;
int FindGreatestSumOfSubArray(int *array,int length)
{
	int start=0;
	int end=0;
	if(NULL==array || length<=0)
	{
		IsInvalidInput=true;
		return 0;
	}
	IsInvalidInput=false;
	int CurSum=0;
	int nGreatestSum=array[0];
	for(int i=0;i<length;i++)
	{
		if(CurSum<=0)
		{
			CurSum=array[i];
			start=i;
		}
		else
			CurSum+=array[i];	
		if(CurSum>=nGreatestSum)
		{
			nGreatestSum=CurSum;
			end=i;
		}
	}
    while(start<=end)
	{
		de.push_back(array[start]);
		start++;
	}
	return nGreatestSum;
}
int main()
{
	cout<<"原数组序列:";
	for(int i=0;i<8;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
	int Greatest=FindGreatestSumOfSubArray(arr,8);
	if(!IsInvalidInput)//用这个全局变量来标记输入是否有效是必要的,因为函数的返回值有可能返回0,那么我们要利用这个标志来判断是程序正常的返回0,还是输入无效返回0;
		cout<<"Greastest: "<<Greatest<<endl;
	else
		cout<<"THE INPUT IS INVALID!"<<endl;
	cout<<"最长子序列为:";
	for(it=de.begin();it!=de.end();it++)
		cout<<*it<<" ";
	cout<<endl;
	system("pause");
	return 0;
}
运行结果:




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值