动态规划|121. 买卖股票的最佳时机

力扣题目地址


前言:
题目很简单,如果只是为了做出这道题,那么有更简单理解的方法,例如贪心,但是这个题目是股票买卖系列的第一道题目,除了做出来之外,还可以通过这道题练习股票买卖系列中所使用的动态规范算法。毕竟一步一步来,从简单题慢慢过渡到困难题比上来直接做困难题要容易一些。目标是攻克股票买卖系列的困难题,因此对于简单题也要重视的去分析与学习。

这道题题目的要求是只能买卖一次,求得盈利的最大值。如果暴力去做,很简单,就是每个点都作为买点,然后该点后的每个点都作为卖点,计算盈利,然后维护一个max即可。暴力可能太慢,适度优化一下也可以:维护一个最小值,不断计算盈利,然后维护一个最大值,这样一次遍历就能求得max。但是这样做明显对于练习动态规划而言没有帮助。


动态规划做法

由于我不是计算机/数学的天纵奇才或者大罗神仙,没法凭空想出一些绚丽的转移方程,然后一步优化到位,因此我只能通过简单的做法一步一步蚕食这道题目。
由于标签中说这道题可以用动态规划去做,那么根据动态规划题目的规律,最后的答案肯定是dp[i]之类的,这个i大概率是天数,也就是维护第i天的最大盈利。因此我只要从第1天一直推到最后一天就可以获得题目的答案。那么问题来了,我该如何从第i天推导到第i+1天呢?或者是从前面的哪一天推导到第i天。

我发现对于一只股票,我只有两种状态,持有或者不持有,这个怎么利用呢?不太清楚,暂时搁浅。我先随便定义一下dp[i]状态的一些属性:
集合:截止第i天时,所有买卖的盈利情况
属性:集合中的盈利最大值

{3,4,6,5} 这个情况,当i=1时,集合就是{0,-1},最大值为0,也就是说dp[1]=0.

那么该如何转移过来呢?
上面讲到了,对于i天,只有两种状态——持有股票或者不持有,因此将dp[i]扩展一下,扩展成dp[i]{0,1},dp[i][0]代表第i天不持有股票时的最大收益,dp[i][1]代表第i天持有股票时的最大收益。稍作分析可得转移方程
d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i ] [ 1 ] + [ i ] ) dp[i][0] = max(dp[i-1][0],dp[i][1]+[i]) dp[i][0]=max(dp[i1][0],dp[i][1]+[i]) d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i ] [ 0 ] − [ i ] ) dp[i][1] = max(dp[i-1][1],dp[i][0]-[i]) dp[i][1]=max(dp[i1][1],dp[i][0][i])
由于本题中只能买卖一次,因此在第二个转移方程中dp[i][0]==0。转移方程如下: d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i ] [ 1 ] + [ i ] ) dp[i][0] = max(dp[i-1][0],dp[i][1]+[i]) dp[i][0]=max(dp[i1][0],dp[i][1]+[i]) d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , − [ i ] ) dp[i][1] = max(dp[i-1][1],-[i]) dp[i][1]=max(dp[i1][1],[i])

Java实现代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        /*
            状态dp
        */
        int n = prices.length;
        int[][] dp = new int[n+1][2];//j∈{0,1},0代表不持有股票,1代表持有股票
        dp[0][0] = 0;
        dp[0][1] = -prices[0];//持有股票时
        for(int i = 1; i < n; i++){
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],-prices[i]);//原本应该为dp[i-1,0]-[i],但由于只能买卖一次,dp[i-1,0]恒为0
        }
        
        return dp[n-1][0];
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值