• 最大子数组问题


    问题描述

    算法导论P38提到
    来源:已知一股票在某一段时间内的变化趋势,问该时间段内何时买入,何时卖出,使得收益最大,求出最大值
    转化:给定一个数组,从中选取一个连续的子数组,使得其元素和在所有的子数组中最大,返回该最大值。

    解决方案

    暴力搜索

    n个元素中选取两个元素,计算两个元素之间的元素的和,将其与max相比,如果比max大,则替换;
    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public static int (int []a){
    int max=0;
    int sum=0;
    for(int i=0;i<a.length;i++){
    for(int j=i;j<a.length;j++){
    for(int k=i;k<=j;k++){
    sum+=a[k];
    }
    if(sum>max){
    max=sum;
    }
    sum=0;
    }
    }
    return max;
    }

    分治策略

    把一个数组从中分开为两个子数组,最大子数组可能的情况是:在左边的子数组,在右边的子数组,含左边的一部分和右边的一部分;对于前两种情况只是将原问题分解为较小的原问题,而第三种情况既然包括左边和右边,一定含有中间的元素,因此很好解决,从左从右遍历即可;然后将这三种情况进行比较,选取最大的部分返回
    这个问题和归并排序是一个道理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    //采用分治策略,时间复杂度为O(nlgn)
    public static int getMaxSum2(int []a){
    return findMaxSub(a,0,a.length-1);
    }
    public static 大专栏  最大子数组问题">int findMaxSub(int[] a,int left,int right){
    if(left==right) return a[left];
    int mid=left+(right-left)/2;
    int leftSum=findMaxSub(a, left, mid);
    int midSum=findMaxCro(a, left,mid, right);
    int rightSum=findMaxSub(a, mid+1, right);
    if(leftSum>midSum&&left>rightSum) return leftSum;
    if(rightSum>leftSum&&rightSum>midSum) return rightSum;
    return midSum;
    }
    public static int findMaxCro(int[] a,int left,int mid,int right){
    int maxleft,maxright;
    int sum=0;
    maxleft=a[mid];
    for(int i=mid;i>=left;i--){
    sum+=a[i];
    if(sum>maxleft){
    maxleft=sum;
    }
    }
    maxright=0;
    sum=0;
    for(int i=mid+1;i<=right;i++){
    sum+=a[i];
    if(sum>maxright){
    maxright=sum;
    }
    }
    return maxleft+maxright;
    }

    DP解法

    第sum[i-1]个元素是前i-1个元素的最大子数组的和,如果sum[i-1]小于0,则sum[i]=a[i],否则sum[i]=sum[i-1]+a[i];最后的结果result取sum[i]的最大值
    sum[i]=max(a[i],sum[i-1]+a[i])
    result=max(result,sum[i])

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //时间复杂度为O(n)
    public static int getMaxSum3(int []a){
    int b=0;
    int sum=0;
    for(int i=0;i<a.length;i++){
    if(b>=0){
    b+=a[i];
    }else{
    b=a[i];
    }
    if(b>sum){
    sum=b;
    }
    }
    return sum;
    }

    参考:
    http://blog.csdn.net/v_JULY_v/article/details/6444021

  • 相关阅读:
    「BZOJ 1000」A+B Problem
    「HNOI 2008」越狱
    蓝桥杯 拼音字母
    蓝桥杯 抽签
    蓝桥杯 快速排序
    [蓝桥杯] 最大比例
    [蓝桥杯] 交换瓶子
    [蓝桥杯] 四平方和
    [蓝桥杯] 剪邮票
    [蓝桥杯] 方格填数
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12326557.html
Copyright © 2020-2023  润新知