美文网首页
最大子数组

最大子数组

作者: 多啦A梦的野比大雄 | 来源:发表于2020-05-31 15:05 被阅读0次

股价每天都在变化,我们希望在一段时间中的最低点买入,在最高点卖出。给定一段时间的股价变化,如何确定最优的买入卖出时间?
如果把每天的股价抽象成一个数组,那么这个问题就是最大子数组问题:
给定一段时间的股价变化数组A,寻找A的和最大的非空连续子数组。
这个问题可以用分治法求解。把数组一分为二,最大的连续非空子数组要么完全在左边,要么完全在右边,要么横跨左右。取左边数组的最大子数组、右边数组的最大子数组、横跨左右的最大子数组中的最大者就得到了原来问题的解。
粗略地看,每次一分为二,递归求解的复杂度为
T(n)=2T(n/2)+\Theta(n)
(\Theta(n)是求解横跨左右的最大子数组的开销)
T(n)=\Theta(nlgn)
代码如下

#include<iostream>
#define inf 9999
using namespace std;

typedef struct res{
    int start,end;
    int msum;
}res;

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

struct res find_max_subarr(int A[],int low,int high){
    if(low==high){
        return res{low,high,A[low]};
    }
    int mid=(low+high)/2;
    res res1=find_max_subarr(A, low, mid);
    res res2=find_max_subarr(A, mid+1, high);
    res res3=find_max_cross_subarr(A, low, mid, high);
    if(res1.msum>res2.msum){
        if(res1.msum>res3.msum)
            return res1;
        else return res3;
    }else if(res2.msum>res3.msum)
        return res2;
    else return res3;
}

int main(){
    int arr[]={1,-1,2,4,5};
    res myres=find_max_subarr(arr, 0, 4);
    cout<<myres.start<<" "<<myres.end<<" "<<myres.msum<<endl;
    return 0;
}

输出

2 4 11

其实,这个问题还有一种更快的递推做法。从左向右扫描数组,A[1..j]的最大子数组要么是A[1..j-1]的最大子数组,要么是以A[j]结尾的子数组。
同时,我们从左往右记录和非负的子数组的开始下标low=m+1。如果A[l...m]之和为负,且m是使从l开始的子数组和为负的最小下标,那么任意的l<i<m,A[i...m]一定是负的(A[l...m]之和为负,A[l...i-1]之和为正)。因此在考虑以A[j]结尾的数组时无需考虑m及m之前的元素,加上这些元素只会使和变小,从m+1开始考虑即可。
这样,我们只需从左向右扫一遍数组,扫每个元素时更新下标low和最大子数组和相关信息。循环执行n次,每次执行常数时间的操作,算法复杂度\Theta(n)
代码如下

#include<iostream>
#define inf 9999
using namespace std;

typedef struct res{
    int start,end;
    int msum;
}res;

struct res find_max_subarr(int A[],int l){
    int Mr=0,low=0;
    int start=0,end=l,M=0-inf;
    for(int i=0;i<l;i++){
        Mr+=A[i];
        if(Mr>M){
            M=Mr;
            start=low;
            end=i;
        }
        if(Mr<0){
            Mr=0;
            low=i+1;
        }
    }
    return res{start,end,M};
}

int main(){
    int arr[]={-1,2,3,-4,1};
    res myres=find_max_subarr(arr, sizeof(arr)/sizeof(int));
    cout<<myres.start<<" "<<myres.end<<" "<<myres.msum<<endl;
    return 0;
}

输出

1 2 5

相关文章

  • 动态规划

    求最大子数组,最大子乘积

  • Leetcode-Medium 152. Maximum Pro

    题目描述 给定一个整数数组nums(有正有负),求最大子数组乘积 思路 求最大子数组乘积问题是求最大子数组之和演变...

  • LeetCode-152-乘积最大子数组

    LeetCode-152-乘积最大子数组 152. 乘积最大子数组[https://leetcode-cn.com...

  • 10《算法入门教程》分治算法之最大子数组问题

    1. 前言 本节内容是分治算法系列之一:最大子数组问题,主要讲解了什么是最大子数组问题,如何利用分治算法解决最大子...

  • 最长子序列问题

    最大子序列最大子序列是要找出由数组成的一维数组中和最大的连续子序列。比如{5,-3,4,2}的最大子序列就是 {5...

  • 53. 最大子序和

    题目链接: 53. 最大子序和 题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最...

  • Leetcode 53 最大子序和

    最大子序和 题目 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最...

  • 分治算法解最大子序列和问题

    最大子序列和问题 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最...

  • 刷leetCode算法题+解析(六)

    最大子序和 题目:给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最...

  • 最大子数组问题

    最近在看算法导论,看到计算最大子数组问题,于是写了一个iOS版本的。 利用分治策略,逐层寻找 最大子数组存在三种情...

网友评论

      本文标题:最大子数组

      本文链接:https://www.haomeiwen.com/subject/ikzlzhtx.html