算法:计算股票的最大收益(动态规划经典案例)

有一道算法题,很有意思:给你一个数组,代表每天股票的买/卖价序列,要求在序列期间内最多只允许买、卖各一次(先买后卖,买要在卖之前),求此期间内的最大收益是多少(可以选择不卖,即收益为0)。举例如下:

  1. 价格序列为[7,1,5,3],则代表第一天股票价格为7,第二天为1,第三天为5,第四天为3(数组长度不定),此时第二天价格为1的时候买入,第三天价格为5的时候卖出,则赚取最大的收益4。如果到了第四天再卖,则只能收益2了。你也不能第一天卖,第二天买,虽然收益是6,但是没有买就卖不出去,只能先买后卖,所以这样是犯规的
  2. 价格序列为[7,1,5,3,6,4],则最大收益为5,即选择第2天买入(买入价1)、第5天卖出(卖出价6)
  3. 价格序列为[7,6,4,3,1],则最大收益率为0,即只能选择买入,但因为价格持续下降,所以无法卖出。这种持续走低的情况还不如不买,也就是收益为0

好了,题目就是这样,怎样计算最大的收益呢?如果用暴力破解,也就是O(n2)的时间复杂度,这样也可以算出来,但是要遍历两遍,相当不经济。有没有遍历一遍就能算出来的办法呢?有的,答案就是动态规划!动态规划能够把n平方的复杂度,简化为n的复杂度,着实厉害啊!

遍历到第一天的时候,我们记住价格,遍历到第二天的时候,我们可以得到前两天的最小值,遍历到第三天的时候,我们可以得到前三天的最小值……当我们遍历到N天的时候,我们可以得到前N天的最小值,然后和N+1天的价格相比,如果N+1天的价格小于等于前N天的最小值,那么肯定是不能卖的,那么就刷新最小值!如果N+1天的价格大于前N天的最小值,那么就计算前N天的最小值与N+1天的价格的差,也就是盈利差,并随时记录下来!如果遇到更大的,就不断刷新,就像一项记录一样,如果打破了就刷新最高值,没有打破就维持原来的最高值。当然盈利差初始化为0,这个也很好理解。算到最后一天,我们不仅得到了所有天数里面的最小价格,还得到了最大的盈利差,这个盈利差就是需要返回的答案!思路分析到这里,下面是实现的代码,供参考:

/**
 * 算法:计算交易日股票最大收益
 * @param prices 各交易日股价
 * @author LiYang
 * @return 最大的股票价差(收益)
 */
public static int maxStockProfit(int[] prices) {
    // 交易日不足2日,则返回0
    if (prices == null || prices.length == 0 || prices.length == 1) {
        return 0;
    }

    // 初始设置历史最低价为第一天的股价
    int lowestPriceInHistory = prices[0];
    // 最大股票价差(收益)初始化为0
    int maxProfit = 0;
    
    // 从第二个交易日开始遍历计算
    for (int i = 1; i < prices.length; i++) {
        // 如果当前交易日股价,比历史最低价要高
        if (prices[i] - lowestPriceInHistory > 0) {
            // 更新最高的股票价差(收益)
            maxProfit = Math.max(prices[i] - lowestPriceInHistory, maxProfit);
        } else {
            // 否则更新历史最低价
            lowestPriceInHistory = prices[i];
        }
    }

    // 返回最终计算的最大股票价差(收益)
    return maxProfit;
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值