分治法解决最大子数组问题 (C/C++)

问题背景

输入:数天内的股价变化情况(+10 代表上涨.-6 代表下降)
输出: 在某天买入,另一天卖出,获利最大的值

算法设计

抽象为一个数组
data={13,3,25,20,3,16,23,18,20,7,12,5,22,15,4,7}
求解最大的子数组.

采用分治的思想,利用中点把数组分为三类:
(设中点为mid,起始low,终点high,子数组界为i,j)
1. 左半部分: lowijmid
2. 跨越中点的部分: lowimidj<high
3. 右半部分: mid<ijhigh
对1,2两种情况进行分治并递归求解,3的算法设计则较为简单.

算法分析

(参见算法导论第四章)
时间复杂度:

T(n)=Θ(1)2T(n2)+Θ(n)n=1n>1

由主公式可得 T(n)=Θ(nlgn)

算法实现

//Copyright by ChestnutHeng.All rights reserved.
#include <iostream>
#define LEN 16
#define MAXNUM 60000
using namespace std;
typedef struct array_info_message  //储存子数组位置和加和的结构体
{
    int low;
    int high;
    int sum;
}array_info;
array_info max_crossed_array(int data[],int low,int mid,int high) //跨越了中点的数组求最大子数组
{
    int left_sum = -MAXNUM;
    int max_left;
    int sum = 0;
    for(int i = mid;i >= low; --i)  //遍历中点左半的和并计算最大值
    {

        sum += data[i];
        if(sum > left_sum)
        {
            left_sum = sum;
        }
        max_left = i;
    }
    int right_sum = -MAXNUM;
    int max_right;
    sum = 0;
    for(int i = mid + 1;i <= high; ++i) //遍历中点右半的和并计算最大
    {

        sum += data[i];
        if(sum > right_sum)
        {
            right_sum = sum;
        }
        max_right = i;
    }
    array_info answer = {max_left,max_right,left_sum + right_sum}; //求出本数组的最大和并返回
    return answer;

}

array_info max_child_array(int data[],int low,int high) //求解最大子数组
{
    int mid;
    if (high == low)  //递归终止条件
        {
            array_info bukket = {low,high,data[low]}; //当只有一个元素时返回它
            return bukket;
        }
    else  mid = (high + low)/2;   //分治
    array_info left_bukket = max_child_array(data,low,mid);
    array_info right_bukket = max_child_array(data,mid+1,high);
    array_info mid_bukket = max_crossed_array(data,low,mid,high);
    if(left_bukket.sum >= mid_bukket.sum && left_bukket.sum >= right_bukket.sum)
    {
        return left_bukket;
    }else if(right_bukket.sum >= mid_bukket.sum && right_bukket.sum >= left_bukket.sum)
    {
        return right_bukket;
    }else return mid_bukket; //找出最优的分治策略


}

int main(int argc, char const *argv[])
{
    int array[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    cout << max_child_array(array,0,LEN-1).sum << endl;
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法伪代码: ``` // 最大数组问题 // 输入:数组 nums,数组起始下标 low,数组结束下标 high // 输出:数组 nums 在下标 low 到 high 之间最大数组的和 function maxSubArray(nums, low, high): // 递归结束条件 if low == high: return nums[low] // 分治解 mid = (low + high) / 2 leftMaxSum = maxSubArray(nums, low, mid) // 左半部分最大数组和 rightMaxSum = maxSubArray(nums, mid+1, high) // 右半部分最大数组和 crossMaxSum = maxCrossSubArray(nums, low, mid, high) // 跨越中点的最大数组和 // 返回三者中最大的值 return max(leftMaxSum, rightMaxSum, crossMaxSum) // 解跨越中点的最大数组和 // 输入:数组 nums,数组起始下标 low,数组中点下标 mid,数组结束下标 high // 输出:数组 nums 在下标 low 到 high 之间跨越中点的最大数组的和 function maxCrossSubArray(nums, low, mid, high): // 计算包含中点的左半部分最大数组和 leftMaxSum = -INF sum = 0 for i = mid downto low: sum = sum + nums[i] leftMaxSum = max(leftMaxSum, sum) // 计算包含中点的右半部分最大数组和 rightMaxSum = -INF sum = 0 for i = mid+1 to high: sum = sum + nums[i] rightMaxSum = max(rightMaxSum, sum) // 返回左右两部分加起来的和 return leftMaxSum + rightMaxSum ``` 算法时间复杂度分析: 该算法的时间复杂度为 $O(nlogn)$,其中 $n$ 为数组的长度。因为该算法是一个分治算法,每次递归都将问题规模减半,因此递归层数为 $logn$。在每层递归中,需要线性时间 $O(n)$ 计算跨越中点的最大数组和,因此总时间复杂度为 $O(nlogn)$。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值