求最大连续子序列和递归深度理解!!!

179 阅读2分钟

求最大区间和

问题描述

给定一个数组X[n] 求解该数组的最大子数组和。子数组 是数组中的一个连续部分。

例如:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

图解

image.png

分解为下面的小区间

哈哈哈

image.png

解析

先分解为最小子问题

最小子问题即只剩一个或两个,得出左、右和从中间出发向左和右的最大值相加,得到小区间最大值

再合并

合并另外一个小区间,已知两小区间最大值,再求解从中点出发的跨越区间最大值,进行得到该两个小区间合并的最大值

最后放大

最后放大到整个数组区间即完成!!

举例

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;
}

参考:最大子数组和(递归分治)详细讲解_最大子数和 讲解-CSDN博客