求解最大连续子数组(分治策略)
算法思想
基于分治策略,将原始问题分解为多个更小规模的子问题,将数组以中心为间隔分为左子数组和右子数组,假设原始问题规模为n,此时将问题分为两个规模n/2的子问题,分别递归地求解两个子问题,两个子数组的最大连续数组,递归直到数组只有一个元素返回(通过查找最大连续过中点子树函数得到),保证得到左右最大连续子数组,回溯后,再考虑跨过中点的中子数组,最后选择左子数组、右子数组和中子数组中最大的作为当前子数组最大连续子数组
,在回溯到上一级,求解出原问题的所有子问题,即可得到最大原始问题的解。
实际上,最大连续子数组有三种情况,分别是在左子数组中、右子数组中、跨过中点的子数组中
,考虑这三种情况即可
实现代码
/*
author : eclipse
email : [email protected]
time : Sun Jun 14 11:18:17 2020
*/
#include <bits/stdc++.h>
using namespace std;
class MaxSubarray {
private:
vector<int> array;
int findMaxCrossingSubarray(int low, int mid, int high, int &maxLeft, int &maxRight);
int findMaxSubarray(int low, int high, int &boundaryLow, int &boundaryHigh);
public:
MaxSubarray(vector<int> v);
void findMaxSubarray();
};
MaxSubarray::MaxSubarray(vector<int> v) {
for (int i = 0; i < v.size(); i++) {
array.push_back(v[i]);
}
}
int MaxSubarray::findMaxCrossingSubarray(int low, int mid, int high, int &maxLeft, int &maxRight) {
int leftSum = -INT_MAX;
int sum = 0;
for (int i = mid; i >= low; i--) {
sum += array[i];
if (sum > leftSum) {
leftSum = sum;
maxLeft = i;
}
}
int rightSum = -INT_MAX;
sum = 0;
for (int i = mid + 1; i <= high; i++) {
sum += array[i];
if (sum > rightSum) {
rightSum = sum;
maxRight = i;
}
}
return leftSum + rightSum;
}
int MaxSubarray::findMaxSubarray(int low, int high, int &boundaryLow, int &boundaryHigh) {
if (low == high) {
boundaryLow = low;
boundaryHigh = high;
return array[low];
} else {
int mid = (low + high) / 2;
int leftLow, leftHigh, leftSum;
leftSum = findMaxSubarray(low, mid, leftLow, leftHigh);
int rightLow, rightHigh, rightSum;
rightSum = findMaxSubarray(mid + 1, high, rightLow, rightHigh);
int crossLow, crossHigh, crossSum;
crossSum = findMaxCrossingSubarray(low, mid, high, crossLow, crossHigh);
if (leftSum >= rightSum && rightSum >= crossSum) {
boundaryHigh = leftHigh;
boundaryLow = leftLow;
return leftSum;
} else if (rightSum >= leftSum && rightSum >= crossSum) {
boundaryHigh = rightHigh;
boundaryLow = rightLow;
return rightSum;
} else {
boundaryHigh = crossHigh;
boundaryLow = crossLow;
return crossSum;
}
}
}
void MaxSubarray::findMaxSubarray() {
int boundaryLow, boundaryHigh, maxSum;
maxSum = findMaxSubarray(0, array.size() - 1, boundaryLow, boundaryHigh);
printf("%d\n", maxSum);
for (int i = boundaryLow; i <= boundaryHigh; i++) {
printf("%d ", array[i]);
}
}
int main(int argc, char const *argv[]) {
int N;
vector<int> v;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
int value;
scanf("%d", &value);
v.push_back(value);
}
MaxSubarray *maxSubarray = new MaxSubarray(v);
maxSubarray->findMaxSubarray();
return 0;
}
输入数据
9
-1 -1 2 3 4 -5 23 -1 2
输出结果
28
2 3 4 -5 23 -1 2
样例图解
框中的为当前子数组最大连续子数组
鸣谢
最后
- 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!