求最大区间和
问题描述
给定一个数组X[n] 求解该数组的最大子数组和。子数组 是数组中的一个连续部分。
例如:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
图解
分解为下面的小区间
解析
先分解为最小子问题
最小子问题即只剩一个或两个,得出左、右和从中间出发向左和右的最大值相加,得到小区间最大值
再合并
合并另外一个小区间,已知两小区间最大值,再求解从中点出发的跨越区间最大值,进行得到该两个小区间合并的最大值
最后放大
最后放大到整个数组区间即完成!!
举例
1 -2 4
左边小区间1和-2 右边小区间为4 左边最大为1 右边最大为4
从中间(-2)出发向左(即区间[1,-2])最大为-1,向右出发(即区间[4]) 最大为4,整个跨越区间最大为-3
最后求得该小区间最大子序列和为4
#include <iostream>
#include <algorithm>
using namespace std;
//求跨越中间元素的最大值
//由于是求跨越中点的最大值,故必须有X[mid]与X[mid+1]这两个元素
//故以这两个元素为起点
int CrossingSubArray(int X[], int low, int mid, int high)
{
//求左侧包含X[mid]元素的最大值
int Sleft = INT_MIN;
int Sum = 0;
//以X[mid]为起点
for (int l = mid; l >= low; l--)
{
//比较加上一个元素的总和 Sleft 与不加上一个元素的总和 Sum 之间的大小
Sum = Sum + X[l];
Sleft = max(Sleft, Sum);
}
//求右侧包含X[mid+1]元素的最大值
int Sright = INT_MIN;
Sum = 0;
//以X[mid+1]为起点
for (int r = mid + 1; r <= high; r++)
{
//比较加下一个元素的总和 Sright 与不加下一个元素的总和 Sum 之间的大小
Sum = Sum + X[r];
Sright = max(Sright, Sum);
}
int S3 = Sleft + Sright;
return S3;
}
//求解最大子数组
int MaxSubArray(int X[], int low, int high)
{
int mid, S1, S2, S3, Smax = 0;
if (low == high)
{
return X[low];
}
else
{
mid = (low + high) / 2;
//分解原问题---->T(n/2)
S1 = MaxSubArray(X, low, mid);
//分解原问题---->T(n/2)
S2 = MaxSubArray(X, mid + 1, high);
//合并问题解---->T(n)
S3 = CrossingSubArray(X, low, mid, high);
Smax = max({ S1, S2, S3 });
return Smax;
}
}
int main()
{
int X[12] = { 1,-2,4,5,-2,8,3,-2,6,3,7,-1 };
int result = MaxSubArray(X, 0, 11);
cout << result;
return 0;
}