最大连续子数组和 动态规划_剑指offer_42_连续子数组的最大和

6e843f75d872a996b2c3a950e9ae7cf5.png

//面试题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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值