题目
输入一个整形数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。
思路一:遍历
从数组的第一个元素开始遍历。用nGreatestSum记录子数组的和的最大值。用nCurSum记录依次累加元素的和。如果nCurSum已经是负数,则可以将nCurSum重新赋值为当前元素的值;否则,继续累加。每遍历一个元素,将nGreatestSum与nCurSum比较,用来更新最大子数组之和。
代码
#include <iostream>
using namespace std;
int FindGreatestSumOfSubArray(int *pData, int nLength)
{
if (pData == nullptr || nLength <= 0)
return 0;
int nCurSum = 0;
int nGreatestSum = 0x80000000; // -2,147,483,648
for (int i = 0; i < nLength; ++i)
{
if (nCurSum < 0)
nCurSum = pData[i];
else
nCurSum += pData[i];
if (nCurSum > nGreatestSum)
nGreatestSum = nCurSum;
}
return nGreatestSum;
}
int main()
{
int arr[] = {1,3,-1,-3,5,3,6,7};
cout << FindGreatestSumOfSubArray(arr, sizeof(arr) / sizeof(int)) << endl;
return 0;
}
思路二:动态规划
代码
#include <iostream>
#include <algorithm>
using namespace std;
int FindGreatestSumOfSubArray(int *pData, int nLength)
{
if (pData == nullptr || nLength <= 0)
return 0;
int* max = new int[nLength];
for (int i = 0; i < nLength; ++i) {
if (0 == i || max[i-1] <= 0)
max[i] = pData[i];
else
max[i] = max[i-1] + pData[i];
}
int ans = *std::max_element(max, max+nLength);
delete[](max);
return ans;
}
int main()
{
int arr[] = {1,3,-1,-3,5,3,6,7};
cout << FindGreatestSumOfSubArray(arr, sizeof(arr) / sizeof(int)) << endl;
return 0;
}
思路三:分治
分治方法根据最大连续子数组存在三种位置的可能:
1 – 出现在数组中间的左边(a[0],a[1]…a[n/2]);
2 – 出现在数组中间的右边(a[n/2+1],…a[n-1]);
3 – 子数组经过了中间。
代码
--------从别人那拷贝
#include<stdio.h>
int MaxSum(int* a,int i, int j)
{
if(i == j) return a[i];
int mid = (i+j)/2;
int num1 = MaxSum(a,i,mid);
int num2 = MaxSum(a,mid+1,j);
int num3 = 0;
int max1 = a[mid],max2 = a[mid+1];
int s1 = 0,s2 = 0;
for(int k=mid; k>=i; k--)
{
s1 += a[k];
if(s1 > max1) max1 = s1;
}
for(int k=mid+1; k<=j; k++){
s2 += a[k];
if(s2 > max2) max2 = s2;
}
num3 = max1+max2;
int max = 0;
max = (num1>num2) ? num1:num2;
max = (num3>max) ? num3:max;
return max;
}
int main(){
int a[] = {
1,-2,3,5,-3,2
};
int maxsum = MaxSum(a,0,5);
printf("%d\n",maxsum);
}