• 代码随想录笔记_动态规划_122买卖股票的最佳时机II


    代码随想录二刷笔记记录

    LC122.买卖股票的最佳时机II


    题目

    股票问题

    给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

    在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

    返回 你能获得的 最大 利润 。

    示例 1:

    输入:prices = [7,1,5,3,6,4]
    输出:7
    解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
    随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
    总利润为 4 + 3 = 7 。

    示例 2:

    输入:prices = [1,2,3,4,5]
    输出:4
    解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
    总利润为 4 。

    示例 3:

    输入:prices = [7,6,4,3,1]
    输出:0
    解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。


    思路分析

    思路

    LC121买卖股票的最佳时机,相同,存在两种状态的状态转移,状态持股(0) ,状态不持股(1)

    动态规划五部曲

    1.确定dp数组及其下标的含义

    dp[i][0] :  i 天持有股票的利润总额
    dp[i][1] :  i 天不持有股票的利润总额
    
    • 1
    • 2

    2.确定递推公式

    dp[i][0] 可以由2个状态推演而来
    第 i 天之前就已经持有股票: dp[i-1][0]
    第 i 天买入股票: dp[i-1][1] - prices[i]
     //表示就是第 i-1 天的现金 - 股票价格
    dp[i][1] 
    第 i 天之前就没有买股票: dp[i-1][1]
    第 i 天卖的股票: dp[i][0] + prices[i] 
     // 表示就是第 i-1 天的现金 + 股票价格
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.初始化

    dp[0][0] :0 天持有股票
    dp[0][0] = -prices[0]
    dp[0][1] :0 天不持有股票
    dp[0][1] = 0
    
    • 1
    • 2
    • 3
    • 4

    4.遍历顺序

    根据题目可得,按照时间顺序从前向后遍历,根据递推公式,i的状态由i-1状态转移而来,因此也是从前向后遍历

    for(int i = 1;i < nums.length;i++){
    //dp[i][1] - price[i] 是和 LC121 唯一的区别
    	dp[i][0] = max(dp[i-1][0],dp[i][1] - prices[i]); 
    	dp[i][1] = max(dp[i-1][1],dp[i][0] + prices[i]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.推演分析

    以 prices = [7,1,5,3,6,4] 为例

    i持股(0)不持股(1)
    0-70
    1max(-7,0 - 1) = -1max(0, -7 + 1) = 0
    2max(-1, -5) = -1max(0,-1+5) = 4
    3max(-1,4-3) = 1max(4,-1+3) = 4
    4max(1,4-6) = 1max(4,1 + 6) = 7
    5max(1, 7 - 4) = 3max(7, 1 + 4) = 7

    代码实现

    完整代码实现

    public int maxProfit(int[] prices) {
    	//初始化
    	int[][] dp = new int[prices.length][2];
    	// 第 0 天持有股票
    	dp[0][0] = -prices[0]; 
    	// 第 0 天不持有股票
    	dp[0][1] = 0; 
    	//遍历顺序
    	for(int i = 1;i < prices.length;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],dp[i-1][0] + prices[i]);
    	}
    	return dp[prices.length-1][1];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    小结

    本题与LC121对比,121只会买入1次,卖出1次。由题意和示例1可知,本题能够买入n次,卖出n次。因此,递推公式需要改变。买卖多次的递推公式为

    dp[i][0] 可以由2个状态推演而来
    // 满仓状态
    第 i 天之前就已经持有股票: dp[i-1][0]
    //表示就是第 i-1 天的现金 - 股票价格
    第 i 天买入股票: dp[i-1][1] - prices[i]
    // 状态转移:空仓 -> 满仓
    dp[i][1] 同理
    // 空仓状态
    第 i 天之前就没有买股票: dp[i-1][1]
    // 状态转移:表示就是第 i-1 天的现金 + 股票价格
    第 i 天卖出股票: dp[i][0] + prices[i]  
    // 状态转移: 满仓 -> 空仓
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    注意:由于题目限制了最多只有一股股票,因此我们可以将持股视为满仓状态,而不持股视为空仓状态。而买入和卖出操作,都是两者之间的状态转移操作。

  • 相关阅读:
    Nodejs -- 前后端身份认证概念及在Express中使用认证(Session,Cookie,JWT)
    基于SSM的选课排课系统
    Android面试题汇总(一)
    threejs绘制多个多边形
    Boolean源码解剖学
    【风控】评分卡建模的流程和要点
    PostgreSQL安全
    微信小程序托福考试资料源码系统完整版(带java后台)
    MATLAB中findsignal函数使用
    组件中的那么属性作用
  • 原文地址:https://blog.csdn.net/Erik_Ying/article/details/126317175