求解最大连续子数组(分治策略)

求解最大连续子数组(分治策略)

算法思想

基于分治策略,将原始问题分解为多个更小规模的子问题,将数组以中心为间隔分为左子数组和右子数组,假设原始问题规模为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

样例图解

框中的为当前子数组最大连续子数组

鸣谢

《算法导论》

最后

  • 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章