最大股票收益问题(数组最大差问题)

最大股票收益问题(数组最大差问题)

问题描述

给定一个数组,存储着按照时间排序的股票价格,第 i 个位置的元素为第i次交易时的股票价格;现假设只允许你进行一次买,然后在某一时刻卖出(单只股票),请设计算法,求解你可能获得的最大收益,如果股价是非增的,则收益为0。

O(n2) 解法

将数组每个元素与其后的所有元素比较,选择增差最大的一对儿。
时间复杂度为:

T(n)=(n1)+(n2)+......+1

O(nlogn) 解法

算法思想

采用分而治之的思想,将数组对半分,则最大收益分以下3中情况:
- 在前半段中买并卖
- 在后半段中买并卖
- 在前半段买,在后半段卖
对于第1种和第2种情况,只需要将其看作一个规模减小的新的问题,也就是迭代我们的算法;对于第3种情况,需要在前半段找最小元素 min ,在后半段找最大元素 max ,则 maxmin 是第3种情况下的可能的最优解。

伪代码

void stock(int K[], int startIndex, int endIndex){
    int length = endIndex - startIndex;
    if(1==length) return 0;
    if(2==length) return K[endIndex]-K[startIndex] > 0 ? K[endIndex]-K[startIndex] : 0;
    if(length>2){
        midIndex = (startIndex+endIndex)/2;
        min = findMin(K, startIndex, midIndex );
        max = findMax(K, midIndex+1, endIndex);
        mayGet = max(stock(K,startIndex,midIndex), stock(K,startIndex,midIndex), max-min);
        return mayGet > 0 ? mayGet : 0;
    }
}

复杂度

T(n)=2T(n2)+n2+n2

解得:
T(n)=O(nlogn)

O(n) 解法

算法思想

预处理数组,转化为求数组最大子段和问题,然后使用最大子段和的求解算法解决该问题。

步骤:

预处理数组

将数组的每一项减去其紧挨着的前一项,首项设为0;
其含义为:将股价数组,变为股价增幅数组。
如:

K = [3,5,1,2,5,8,9,6]

处理之后变为

K = [0,2,-4,1,3,3,1,-3]

预处理之后,原问题就转化为求数组最大子段和的问题。
例如,在原数组中很显然最大收益为 91=8 ,则在预处理之后的数组中,只需要从 1 之后的第一个元素开始到9所对应的元素为止,进行累加即可,为 1+3+3+1=8
这其中的道理也很简单,因为预处理之后的数组存储的正是增量,将两个元素之间的所有增量累加,得到的正是两个元素的差值。
预处理算法伪代码:

void preProcess(int K[], int n){
    int i;
    i = n-1;
    while(i>0){
        K[i] = k[i]-k[i-1];
    }
    K[0] = 0;
}
求最大子段和

那么最大收益的问题就转化成为了求数组最大子段和的问题,针对最大子段和采用以下算法。
先看伪代码:

void maxSegSum(int K[], int n){
    int i;
    int maxSum=-MAXINT;
    int tempSum=0;
    for(i=0; i<n; i++){
        tempSum += K[i];
        if(tempSum>maxSum) maxSum = tempSum;
        if(tempSum<0) tempSum=0;
    }   
    print("max sub-segment sum is %f", maxSum);
}

算法描述:
- 从头到尾遍历数组,维持两个全局变量,maxSum记录最优解,tempSum记录从某个位置开始的子段和;
- 每次更新tempSum之后,先和maxSum进行比较,大于maxSum则更新maxSum;然后检查tempSum是否小于0,如果否继续累加,如果是则将tempSum归零;
- 这样遍历一遍数组之后,得到的maxSum就是该数组的最大子段和。

算法综述

  • 预处理数组,转化为最大子段和问题 O(n)
  • 使用以上算法求解最大子段和问题 O(n)

时间复杂度

T(n)=O(n)+O(n)

即:
T(n)=O(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值