求解最大連續子數組(分治策略)
算法思想
基於分治策略,將原始問題分解爲多個更小規模的子問題,將數組以中心爲間隔分爲左子數組和右子數組,假設原始問題規模爲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
樣例圖解
框中的爲當前子數組最大連續子數組
鳴謝
最後
- 由於博主水平有限,不免有疏漏之處,歡迎讀者隨時批評指正,以免造成不必要的誤解!