问题描述
给定一个数组a,数组中的元素有正数也有负数,数组中的一个或连续多个数组成一个子数组。求这些所有子数组的最大和。
例如:a={-1, 2, 3, -4, 5},它的最大和应该是:2+3+(-4)+5=6。
暴力遍历法
从i=0开始到i=length-1,开始往后加,遍历所有的子数组,然后比较每一个子数组的和。
时间复杂度O(n^2),空间复杂度O(1)。代码如下:
#include <iostream>
using namespace std;
int calMaxSumOfArray(int arr[],int n)
{
if (n == 0)
{
return 0;
}
if (n == 1)
{
return arr[0];
}
int sum = arr[0];//初始化sum
int tmp;
for (int i = 0; i < n - 1; i++)
{
tmp = arr[i];
if (sum < tmp)
{ //这里需要判断一下该数是否比sum大,因为有可能这个数是整个数组的最大子序列和
sum = tmp;
}
//开始从arr[i]往它之后遍历,相加,再跟sum对比
for (int j = i + 1; j < n; j++)
{
tmp = tmp + arr[j];
if (sum < tmp)
{
sum = tmp;
}
}
}
return sum;
}
int main()
{
int arr[] = { -1, 2, 3, -4, 5 };
int n = sizeof arr / sizeof(arr[0]);
cout << calMaxSumOfArray(arr, n) << endl;
return 0;
}
动态规划
状态方程:max(dp[i]) = getMax(max(dp[i-1]) + arr[i], arr[i])。
我们从头开始遍历数组,遍历到arr[i]时,最大和可能是dp[i-1])+arr[i],也可能是arr[i]。时间复杂度O(n),空间复杂度O(n)。代码如下:
#include <iostream>
using namespace std;
int max(int a, int b)
{
return a > b ? a : b;
}
int calMaxSumOfArray(int arr[],int n)
{
if (n == 0)
{
return 0;
}
if (n == 1)
{
return arr[0];
}
int sum = arr[0];
int tmp = arr[0];
for (int i = 1; i < n; i++)
{
tmp = max(tmp + arr[i], arr[i]);
if (sum < tmp)
{
sum = tmp;
}
}
return sum;
}
int main()
{
int arr[] = { -1, 2, 3, -4, 5 };
int n = sizeof arr / sizeof(arr[0]);
cout << calMaxSumOfArray(arr, n) << endl;
return 0;
}
非动态规划的方法
我们从头开始累加,初始sum=arr[0],临时变量tmp=arr[0]。从i=1开始,tep = tep+arr[i],如果tmp小于0,并且发现前面加过的数小于sum,那么舍弃前面的累加值,从i+1开始。代码如下:
#include <iostream>
using namespace std;
int calMaxSumOfArray(int arr[],int n)
{
if (n == 0)
{
return 0;
}
if (n == 1)
{
return arr[0];
}
int sum = arr[0];
int tmp = arr[0];
for (int i = 1; i < n; i++)
{
if (tmp < 0)
{
tmp = 0;
}
tmp = tmp + arr[i];
if (sum < tmp)
{
sum = tmp;
}
}
return sum;
}
int main()
{
int arr[] = { -1, 2, 3, -4, 5 };
int n = sizeof arr / sizeof(arr[0]);
cout << calMaxSumOfArray(arr, n) << endl;
return 0;
}