题目
一个有N个整数元素的一维数组,{A[0]…A[n-1]},求该数组所有子数组中的最大和。 题意明确:
- 题目中说的子数组是连续的;
- 题目只需要求和,并不需要返回子数组的具体位置;
- 数组的元素是整数,所以数组可能包含有正整数,零和负整数;
例: 数组[ 1,-2,3,5,-3,2 ]返回8;
分析
《编程之美》P183-188中详细讲述了,该题目从最初暴力O(n^3)的解法,优化到最后O(N)的步骤;
代码
/*
2.14 求数组的子数组之和的最大值
*/
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
/*方法一:罗列所有的子数组,求每个子数组的和,时间复杂度O(n^3)*/
int maxSubSum(const vector<int> &nums)
{
if (nums.empty())
{
return 0;
}//if
int len = nums.size();
int maxSum = INT_MIN, tmpSum = 0;
for (int i = 0; i < len; ++i)
{
for (int j = i; j < len; ++j)
{
/*清0临时子数组的和*/
tmpSum = 0;
/*求i到j的子数组之和*/
for (int k = i; k <= j; ++k)
{
tmpSum += nums[k];
}//for
if (tmpSum > maxSum)
{
maxSum = tmpSum;
}//if
}//for
}//for
return maxSum;
}
/*方法二:注意到sum[i...j] = sum[i-1 ... j] + nums[j] , 复杂度降低到O(n^2)*/
int maxSubSum2(const vector<int> &nums)
{
if (nums.empty())
{
return 0;
}//if
int len = nums.size();
int maxSum = INT_MIN, tmpSum = 0;
for (int i = 0; i < len; ++i)
{
tmpSum = 0;
for (int j = i; j < len; ++j)
{
tmpSum += nums[j];
/*从i到j的子数组之和为tmpSum*/
if (tmpSum > maxSum)
maxSum = tmpSum;
}//for
}//for
return maxSum;
}
/*方法三:分治法的思想,分为规模减半的子问题,通过递归解决;复杂度O(nlogn)*/
/*方法四:动态规划max{A[0], A[0]+start[1], ALL[1]},时间复杂度O(N),空间复杂度O(N)*/
int maxSubSum4(const vector<int> &A)
{
if (A.empty())
{
return 0;
}//if
int len = A.size();
/*Start数组中存放的是,以下标i对应元素为起始点的最大子数组之和*/
vector<int> Start(len, 0);
/*All数组中存放的是,从下标[i...len-1]实际最大子数组之和*/
vector<int> All(len, 0);
/*从数组末尾向前遍历,知道数组首部*/
Start[len - 1] = A[len - 1];
All[len - 1] = A[len - 1];
for (int i = len - 2; i >= 0; --i)
{
Start[i] = max(A[i], A[i] + Start[i + 1]);
All [i] = max(Start[i], All[i + 1]);
}//for
return All[0];
}
/*方法五:四的改进,空间复杂度减低到O(1)*/
int maxSubSum5(const vector<int> &A)
{
if (A.empty())
{
return 0;
}//if
int len = A.size();
int nStart = A[len - 1], nAll = A[len - 1];
for (int i = len - 2; i >= 0; --i)
{
nStart = max(A[i], nStart + A[i]);
nAll = max(nStart, nAll);
}//for
return nAll;
}
/*方法六:线性时间复杂度*/
int maxSubSum6(const vector<int> &A)
{
if (A.empty())
{
return 0;
}//if
/*求数组A的长度*/
int n = A.size();
int maxSum = A[n - 1], tmpSum = A[n - 1];
for (int i = n - 2; i >= 0; --i)
{
if (tmpSum < 0)
{
tmpSum = 0;
}//if
tmpSum += A[i];
if (tmpSum > maxSum)
maxSum = tmpSum;
}//for
return maxSum;
}
int main()
{
vector<int> A = { 1,-2,3,5,-3,2 };
cout << maxSubSum(A) << endl;
cout << maxSubSum2(A) << endl;
cout << maxSubSum4(A) << endl;
cout << maxSubSum5(A) << endl;
cout << maxSubSum6(A) << endl;
system("pause");
return 0;
}