输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。
方法一、穷举法
列举所有的连续数组。列举方法,首先可以选择在数组的任意位置开始,变量i。然后,选择在位置变量i后的最终位置,变量j。最后,对位置i和位置j之间的所有元素进行相加。这样就列举了所有的连续数组。三层循环,时间复杂度为O(N3)
int maxArray2(int *pArray,int nsize) { int sum=0; int maxsum=-10000000; for(int i=0;i<nsize;++i)//可以在任意位置开始 { for(int j=i;j<nsize;++j)//结束的位置只能在i或i后 { for(int k=i;k<=j;++k)//对位置i和位置j之间的元素进行相加 { sum=sum+pArray[k]; } //如果这个连续数组的和比sum大,则记录 if(maxsum<sum)// maxsum=sum; //计算下一个连续数组的和前需清零 sum=0; } } return maxsum; }
二、DP方法
其实对于这个问题,可以划分为两个子问题。
(1)从哪个位置开始加
(2)加多少个元素
对于第一个问题,我们看看数组1, -2, 3, 10, -4, 7, 2, -5,如果从第一个元素开始加,第一个元素和第二个元素的和为1+2=-1,第二个元素是负的也不合适。因为如果最大的连续数组包含第一个和第二元素或者包含第二个元素,我们可以从最大的连续数组中,找出更大连续数组,排除第一个和第二个元素或者排除第二个元素就可以了。
对于第二个问题,我们可以通过设置变量解决,我们可以一直加,记录下最大的maxsum即可。
从这两个思路应该能比较好的理解下面的这个算法。这也有些分治的思想在里面,最大的连续数组到底在哪个部分,在1还是在-2, 3, 10, -4, 7, 2, -5中,在1,-2中,还是在3, 10, -4, 7, 2, -5中。
int maxArray(int *pArray,int nsize) { int sum=0; int maxsum=-10000000; for(int i=0;i<nsize;++i) { sum=sum+pArray[i]; //记录下最大的sum if(maxsum<sum) maxsum=sum; //如果sum<0要从新位置开始 if(sum<0) sum=0; } return maxsum; }