121. 买卖股票的最佳时机
文章讲解:https://programmercarl.com/0121.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA.html
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
视频讲解:https://www.bilibili.com/video/BV1Xe4y1u77q/
dp数组定义:
递推公式:
确定初始化值:
如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来:
如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来:
自己第一次实现的错误,在实现过程中,把递推公式,理解成第i天买入。而代码随想录的概念是第i天持有股票,或者不持有股票,这里指的是有没有股票,而不是第i天做买入、卖出的动作。
自己实现时的问题代码:
public int maxProfit(int[] prices) {
// 动态规划五步曲
// 1. 确定dp数组定义,dp[i][0]和dp[i][1],dp[i][0]表示第i天时,不持有第i天股票的最大价值。dp[i][1]表示第i天,持有第i天股票的最大价值
int[][] dp = new int[prices.length][prices.length];
// 2. 确定递推公式
// 2.1 第i天时不持有第i天股票的价值和前一天的价值一样 dp[i][0] = dp[i-1][0];
// 2.2 第i天持有第i天股票的价值为 dp[i][1] = -prices[i]。因为这里只能买卖一次
// 3. 确定初始值
dp[0][0] = 0;
dp[0][1] = 0 - prices[0];
// 4. 确定遍历顺序,因为值是从i-1推到i的,因此从小到大遍历。
for(int i = 1; i < prices.length; i++){
dp[i][0] = dp[i-1][0];
dp[i][1] = 0 - prices[i];
}
return Math.max(dp[prices.length - 1][0],dp[prices.length - 1][1]);
}
修改后的代码:
public int maxProfit(int[] prices) {
// 动态规划五步曲
// 1. 确定dp数组定义,dp[i][0]和dp[i][1],dp[i][0]表示第i天时,不持有第i天股票的最大价值。dp[i][1]表示第i天,持有第i天股票的最大价值
int[][] dp = new int[prices.length][prices.length];
// 2. 确定递推公式
// 第i天持有股票即dp[i][0],可能之前就持有了,可能是第i天买入:Math.max(dp[i - 1][0], -prices[i]);
// 第i天不持有股票即dp[i][1],可能是之前就不持有了,可能是第i天卖掉:Math.max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
// 3. 确定初始值
dp[0][0] -= prices[0];
dp[0][1] = 0;
// 4. 确定遍历顺序,因为值是从i-1推到i的,因此从小到大遍历。
for(int i = 1; i < prices.length; i++){
// 第i天持有股票即dp[i][0],可能之前就持有了,可能是第i天买入
dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
// 第i天不持有股票即dp[i][1],可能是之前就不持有了,可能是第i天卖掉
dp[i][1] = Math.max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
}
return dp[prices.length - 1][1];
}
122.买卖股票的最佳时机II
文章讲解:https://programmercarl.com/0122.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAII%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
视频讲解:https://www.bilibili.com/video/BV1D24y1Q7Ls/
和121. 买卖股票的最佳时机的题目类似,但是该题目有了多次的买与卖,121题只有一次买卖。最大的区别就是买入和卖出最大值都需要关心上一天的值。
买入和卖出最大值都需要关心上一天的值。
自己实现这里递推公式处理错了,自己实现的错误代码:
public int maxProfit(int[] prices) {
if(prices.length == 1){
return 0;
}
// 动态规划五步骤
// 1. 确定dp定义 dp[i][0]:第i天,未持有股票的最大价值;dp[i][1],第i天,持有股票的最大价值
int[][] dp = new int[prices.length][prices.length];
// 2. 确定推导公式
// 2.1 第i天,未持有股票,可能之前就一直不持有dp[i][0] = dp[i - 1][0] ,也可能第i天卖了,dp[i][0] = dp[i - 1][0] + prices[i]
// 2.2 第i天,持有股票,可能之前就一直持有dp[i][1] = dp[i-1][1],也可能第i天买入,dp[i - 1][1] - prices[i]
// 3. 确定初始化值
dp[0][0] = 0;
dp[0][1] -= prices[0];
// 4. 确定遍历顺序(这里错误)
for(int i = 1; i < prices.length; i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][0] + prices[i]);
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][1] - prices[i]);
}
return dp[prices.length - 1][0];
}
这里的推导公式应该要考虑到上一节点也会做买卖。
当买入股票时,可能会有之前买卖的利润,因此最大值的话用上一节点不持有股票的最大价值来计算才会是最大值。因此 dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
同不持有股票时,存在卖和不卖的情况,卖的情况要考虑到上一节点持有股票时的最大利润做加法 dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);
今日学习1h,学习了下股票最佳时机。核心的逻辑就是要使用持有时的最大价值和不持有时的最大价值来计算。使用二维数组+动态规划五步骤做逻辑处理。