//面试题42.连续子数组的最大值
//题目:输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。
//求所有子数组的和的最大值,要求时间复杂度是O(n)。
/*
思路:
假设给定一个数组{1,-2,3,10,-4,7,2,-5}
第一步:先初始化子数组的和为0,然后加上第一个数字1,此时和为1;将子数组的和的最大值更新为;
第二步:继续向下加,加上-2,此时和为-1,此时子数组的和的最大值仍为1;
第三步:如果在前两步的基础上继续加上第三个数3,那么-1+3=2<3,和为负数,那么接下来加上的值肯定比本身要小,所以不能在之前和的基础上继续加,只能以新的数字为子数组的起点,即3,此时
子数组的和的最大值更新为3;
第四步:继续向下加,加上10,此时和为13,将子数组的和的最大值更新为13;
第五步:继续向下加,加上-4,此时和为9,子数组的和的最大值仍为13;
第六步:继续向下加,加上7,此时和为16,子数组的和的最大值更新为16;
第七步:继续向下加,加上2,此时和为18,子数组的和的最大值更新为18;
第八步:继续向下加,加上-5,此时和为13,子数组的和的最大值仍为18.
总结上述过程,我们发现,当子数组的和为负值的时候,我们需要在即将加到的下一个数字开始一个新的子数组,不能再在之前累加的基础上继续往下加,因为+负数<下一个数字;
如果是正数,我们就继续向下加。
上述过程可以采用动态规划的思想,我们假设以第i个数字结尾的子数组的最大和为f(i),我们需要求出max[f(i)],其中0≤i<n
f(i)={ pDatap[i], i=0或者f(i--1)≤0
f(i-1)+pData[i] i≠0并且f(i-1)>0
动态规划的问题:一般采用递归实现,但最终都会采用循环编码。
*/
#include<iostream>
using namespace std;
bool g_InvalidInput;//输入无效标识
int FindGreatestSumOfSubArray(int*pData, int nLength)
{
//鲁棒性
if (pData == nullptr || 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;
}
//===========================测试代码=====================
void Test(const char*testname, int*pData, int nLength, int expected)
{
if (testname != nullptr)
printf("%s begins:n", testname);
if (FindGreatestSumOfSubArray(pData, nLength) == expected)
printf("Passed.n");
else
printf("Failed.n");
}
int main()
{
int pData1[] = { 1,2,3,4,5,6 };
Test("Test01", pData1, sizeof(pData1) / sizeof(int), 21);
int pData2[] = { 1,2,-3,4,5,6 };
Test("Test02", pData2, sizeof(pData2) / sizeof(int), 15);
int pData3[] = { -1,-2,-3,-4,-5,-6 };
Test("Test03", pData3, sizeof(pData3) / sizeof(int), -1);
system("pause");
return 0;
}