1、题目:输入一个整型数组,数组里有正数也有负数,数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为{1,-2,3,10,-4,7,2,-5},和最大的子数组为{3,10,-4,7,2},因此输出为该子数组的和为18。
直观想法是枚举出数组所有子数组并求出他们的和。
一个长度为n的数组,总共有n(n+1)/2个子数组。计算出所有子数组的和,最快也需要O(n^2)的时间。
解法一:举例分析数组的规律
试着从第一个数字开始的子数组的和会小于从第三个数字开始的子数组的和,因此不用考虑从第一个数字开始的子数组,之前累计的和也被抛弃。把之前可能是最大的子数组的和保存起来。
bool g_InvalidInput = false;
int FindGreatestSumOfSubArray(int *pData, int nLength)
{
if((pData == NULL) || (nLength <= 0))
{
g_InvalidInput = true;
return 0;
}
g_InvalidInput = false;
int nCurSum = 0;
int nGreatestSum = 0x80000000;
for(int i=0; i<nLength; ++i)
{
if(nCurSum <= 0)
nCurSum = pData[i];
else
nCurSum += pData[i];
if(nCurSum > nGreatestSum)
nGreatestSum = nCurSum;
}
return nGreatestSum;
}
要考虑无效的输入,比如输入的数组参数为空指针、数组长度小于等于0等情况。此时若让函数返回0,则不能区分子数组的和的最大值是0的情况,因此定义了一个全局变量来标记是否输入无效。
解法二:动态规划法
如果用函数f(i)表示以第i个数字结尾的子数组的最大和,那么我们需要求出求出max[f(i)],其中0<=i<n。
递归公式:f(i) = pData[i] i=0或f(i-1)<=0;
f(i) = f(i-1)+pData[i] i !=0 且f(i-1)>0