最大子数组问题(分治法)--【算法导论】

这题的思想是书上的(《算法导论》),代码当然也是按照书上伪码写出的;

之前已用动态规划解决这个问题,所以问题也不用多说,简述如下:

《算法导论》中引入这个问题是通过股票的购买与出售,经过问题转换,将前一天的当天的股票差价重新表示出来,即转为了一个最大子数组的问题,具体内容我不多说,转的内容是:

13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7

找到这连续的16个数里面的连续和最大的子数组;

说一下书中的思想吧(语言组织是书中的,自认总结不会比书上好):

假定我们要寻找子数组A[low..high]的最大子数组,使用分治法意味着我们要将子数组划分为两个规模尽可能相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后求解两个子数组A[low..mid]和A[mid + 1..high]。所以,A[low..high]的任何连续子数组A[i..j]所处的位置必然是三种情况之一:

1.完全位于子数组A[low..mid]中, 因此low<=i<=j<=mid;

2.完全位于子数组A[mid + 1..high]中,因此mid<=i<=j<=high;

3.跨越了中点,因此low<=i<=mid<j<=high;

因此,A[low..high]的一个最大子数组所处的位置必然是这三种情况之一。实际上,A[low..high]的一个最大子数组必然是完全位于A[low..mid]中、完全位于A[mid + 1..high]中或者跨越中点的所有子数组中和最大者。

代码:

#include <iostream>

const int Infinite = -10000;
//int max_left = 0;
//int max_right = 0;

using namespace std;

int FindMaxCrossSubarray(int A[], int low, int mid, int high)  //跨越
{
    int left_sum = Infinite;
    int sum = 0;
    for (int i = mid; i >= low; i--)  //左半部的最大子数组
    {
        sum += A[i];
        if (sum >left_sum)
        {
            left_sum = sum;
            //max_left = i;
        }
    }

    int right_sum = Infinite;
    sum = 0;
    for (int i = mid + 1; i <= high; i++)  //右半部的最大子数组
    {
        sum += A[i];
        if (sum > right_sum)
        {
            right_sum = sum;
            //max_right = i;
        }
    }
    return left_sum + right_sum;
}

int FindMaxSubarray(int A[], int low, int high)
{
    int left_sum, right_sum, cross_sum;
    if (high == low)  //一个元素
    {
        return A[low];
    }
    else
    {
        int mid = (low + high) / 2; //分治
        left_sum = FindMaxSubarray(A, low, mid);  //前半部
        right_sum = FindMaxSubarray(A, mid + 1, high);  //后半部
        cross_sum = FindMaxCrossSubarray(A, low, mid, high);  //跨越前后

        if (left_sum >= right_sum && left_sum >= cross_sum)  //最大子数组在左边
            return left_sum;

        else if (right_sum >= left_sum && right_sum >= cross_sum)  //右边
            return right_sum;

        else  //跨越
            return cross_sum;
    }
}

int main()
{
    int a[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
    //int a[] = {23, -4};
    int length = sizeof(a) / sizeof(int);

    cout<<FindMaxSubarray(a, 0, length - 1)<<endl;
    //cout<<"最大子序列的下标:"<<max_left<<"->"<<max_right;
    return 0;
}


 

欢迎指点,o(∩_∩)o

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值