《算法导论》分治策略——最大子数组

给定一个数组A,若存在如下序列A[i···j]满足
《算法导论》分治策略——最大子数组_第1张图片
则称序列A[i···j]为数组A的最大子数组。

分:
这里假设数组长度为2的次幂,我们把每次数组每次二等分,获得三个下标low,mid,high,其中mid为被等分的两个数组的中点,low为左边数组的最小下标,high为右边数组的最大下标。那么对于子数组A[low···high]来说,最大子数组的位置只可能是一下三种情况:

  • 完全位于左边的数组A[low···mid]中,及 low<=i<=j<=mid。
  • 完全位于右边的驻足A[mid+1···high]中,及 mid+1<=i<=j<=high。
  • 跨越了中点,及low<=i<=mid < j<=high。

因此,我们可以每次去递归地解决A[low···high],因为每个子问题都是最大子数组问题。

治:
既然已经将问题进行分解了,那么必须对每个问题进行合并,因为每次分割后当前序列的最大子数组只可能是上述的三种情况之一,返回当前序列的最大子数组即可。那么如此递归下去,最后得到的一定是最大子数组。

过程如图:

合并自问题的过程就是寻找分割后的三种情况下子数组最大的情况,伪代码如下:

Find_max_crossing_subArray(A,low,mid,high)
{
    left_sum=0;
    max_left=mid;
    sum=0;
    for(i=mid;i>=low;i--)
    {
        sum+=A[i];
        if(sum>left_sum)
        {
            left_sum=sum;
            max_left=i;
        }
    }
    right_sum-0;
    max_right=mid+1;
    sum=0;
    for(i=mid+1;i<=high;i++)
    {
        sum+=A[i];
        if(sum>right_sum)
        {
            right_sum=sum;
            max_right=i;
        }
    }
    return (max_left,max_right,left_sum+right_sum);
}

分解子问题伪代码如下:


Find_max_subArray(A,low,high)
{
    if(low==high)
        return (low,high,A[low]);

    mid=(low+high)/2;

    (left_low,left_high,left_sum)=Find_max_subArray(A,low,mid);

    (right_low,right_high,right_sum)=Find_max_subArray(A,mid+1,high);

    (cross_low,cross_high,cross_sum)=Find_max_crossing_subArray(A,low,mid,high);

    if(left_sum>right_sum && left_sum>cross_sum)
        return (left_low,left_high,left_sum);

    if(right_sum>left_sum && right_sum>cross_sum)
        return (right_low,right_high,right_sum);

    return (cross_low,cross_high,cross_sum);

}

C++代码如下:

#include 

using namespace std;

int* find_cross_maxSubArray(int* A, int low, int mid, int high);
int* find_maxSubArray(int* A, int low, int high);


int main()
{
    int A[] = { 13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 };
    int* p = find_maxSubArray(A, 0, 15);
    cout << p[0] << " " << p[1] << " " << p[2] << endl;
    system("pause");
}

int * find_cross_maxSubArray(int * A, int low, int mid, int high)
{
    int* p = new int[3];
    int left_sum = -1, right_sum = -1, sum = 0, max_left = mid ,max_right = mid + 1;
    if (low == high)
    {
        p[0] = low;
        p[1] = high;
        p[2] = A[low];
        return p;
    }
    else
    {
        for (int i = mid; i >= low; i--)
        {
            sum += A[i];
            if (sum > left_sum)
            {
                left_sum = sum;
                max_left = i;
            }
        }
        sum = 0;
        for (int i = mid+1; i <=high; i++)
        {
            sum += A[i];
            if (sum > right_sum)
            {
                right_sum = sum;
                max_right = i;
            }
        }
        p[0] = max_left;
        p[1] = max_right;
        p[2] = left_sum + right_sum;
        return p;
    }
}

int * find_maxSubArray(int * A, int low, int high)
{
    int* p = new int[3];
    int* q = new int[3];
    int* r = new int[3];
    int mid;
    if (low==high)
    {
        p[0] = low;
        p[1] = high;
        p[2] = A[low];
        return p;
    }
    else
    {
        mid = (low + high) / 2;
        p = find_maxSubArray(A, low,mid);
        q = find_maxSubArray(A, mid + 1, high);
        r = find_cross_maxSubArray(A, low, mid, high);
        if (p[2] > q[2] && p[2] > r[2])
            return p;
        if (q[2] > p[2] && q[2] > r[2])
            return q;
        return r;
    }
}

你可能感兴趣的:(算法导论)