每天学习一算法系列(4) (输入一个整形数组,数组里有正数也有负数,数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和)

题目:

输入一个整形数组,数组里有正数也有负数,数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。

题目来源于:http://blog.csdn.net/v_JULY_v/archive/2010/11/12/6004660.aspx

 

思路一:

老实说我一开始看到该题目的时候到想到解法还是花了点时间,具体思路是这样,因为时间复杂度是0(n),所以我们只能用一次遍历就要求出最大的子数组和,所以我的想法是这样:以空间换取时间,用一个和原来数组一样大的临时数组记录遍历过程中的和,遍历过程中依次对每个Item都同样进行以下的动作:当遇到负数的时候,就把当前的Sum值记录到临时数组中,然后判断当前的Item的绝对值是否大于Sum,如果大于,将Sum恢复为原来的初始值,也就是Sum = 0,如果Item的绝对值小于Sum的话就把Sum += Item值。当然如果遍历过程中遇到的Item > 0的情况,直接Sum += Item.等到遍历结束后,从临时数组中捉取最大值就是最大的子数组和的值。

 

代码如下:

 

<textarea class="cpp" rows="15" cols="50" name="code"> assert(NULL != pnArray); if (1 == nSize) return *pnArray; int *pnSum = new int[nSize + 1]; assert(NULL != pnSum); int i32Sum = 0, i32CurValue = 0, i32Index = 0; for (int i32I = 0; i32I &lt; nSize; i32I++) { i32CurValue = *(pnArray + i32I); if (i32CurValue &gt;= 0) { i32Sum += i32CurValue; } else if ((i32CurValue &lt; 0)) { *(pnSum + i32Index++) = i32Sum; i32Sum = (abs(i32CurValue) &gt; i32Sum) ? 0 : (i32Sum + i32CurValue); } } pnSum[i32Index] = i32Sum; if (0 != i32Index) { i32Sum = *pnSum; for (int i32J = 1; i32J &lt;= i32Index; i32J++) { if (*(pnSum + i32J) &gt; i32Sum) { i32Sum = *(pnSum + i32J); } } } delete [] pnSum; return i32Sum;</textarea>  

 

思路二:

其实这道题只要一次遍历就可以求出最大的子数组和,而且是很简单的就解决了,具体想法是这样,不断的累加每个数组元素,并用一个变量保存当前的最大值,累加的过程一直和该变量进行比对,如果大于最大值,就把当前的最大值保存下来,反复如此就可以求出最大值.

上面给出的算法太复杂,以下的算法是在上面的基础上进行改进,而且是很容易理解。代码如下:
< textarea class="c-sharp" rows="15" cols="50" name="code">int MaxSum(int* a, int n) { int nSum = 0; int nValue=0; for(int i = 0; i &lt; n; i++) { if (nValue &lt;= 0) nValue = a[i]; else nValue += a[i]; if(nSum &lt; nValue) nSum = nValue; } return nSum; } int _tmain(int argc, _TCHAR* argv[]) { int anAry[] = {-2, 10,12, -20, 33}; //int nMaxValue = MaxSubArraySum(anAry, sizeof(anAry)/sizeof(int)); int nMaxValue = MaxSum(anAry, sizeof(anAry)/sizeof(int)); cout &lt;&lt; &quot;最大的子数组和为:&quot; &lt;&lt; nMaxValue &lt;&lt; endl; return 0; }</textarea>

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值