最大子段和(分而治之)
分治法\(O(n\log{n})\)
按照“分而治之”的思想,将整个数据区间从中间一分为二,这样我们就将求整个区间的最大子列和转换为求小区间的最大子列和。
设区间左端为left,区间右端为right,区间中间为middle。
思考一下,求小区间的子列和一共存在一下三种情况:
- 求左区间的最大子列和:
[left, middle]
- 求右区间的最大子列和:
[middle + 1, right]
- 求从左区间横跨至右区间的最大子列和
代码实现
#include <iostream>
#include <cmath>
using namespace std;
int K;
const int N = 1e7;
int arr[N];
/*从左区间横跨至右区间的情况*/
int getSpecialSum(int left, int right)
{
int middle = (left + right) / 2;
int leftSum = 0, leftSumMax = arr[middle];
int rightSum = 0, rightSumMax = arr[middle + 1];
for (int i = middle; i >= left; i--)
{
leftSum += arr[i];
leftSumMax = max(leftSum, leftSumMax);
}
for (int i = middle + 1; i <= right; i++)
{
rightSum += arr[i];
rightSumMax = max(rightSum, rightSumMax);
}
return leftSumMax + rightSumMax;
}
/*主体*/
int getMaxSum(int left, int right)
{
if (left == right)
return arr[left];
else {
int middle = (left + right) / 2;
int leftSumMax = getMaxSum(left, middle);
int rightSumMax = getMaxSum(middle + 1, right);
int specialSumMax = getSpecialSum(left, right);
return max(max(leftSumMax, rightSumMax), specialSumMax);
}
}
int main()
{
cin >> K;
for (int i = 0; i < K; i++) cin >> arr[i];
cout << getMaxSum(0, K - 1) << endl;
return 0;
}