所用代码 java
dp[i] [0] 、dp[i] [1] :在第i天持有股票所获得的最大利润为dp[i] [0] ;第 i天不持有股票dp[i] [1] 。所以我们在第i天的时候有持有和不持有股票这两种状态,且持有和不持有并不代表着这一天买或者卖,也可能是前面以及买入或者卖出的情况。
递推公式:
dp[i] [0] = max(dp[i-1] [0], -prices[i])
dp[i-1] [1] = max(dp[i-1] [1], dp[i-1] [0] + prices[i])
初始化:
遍历顺序:1<=i
打印dp数组
返回结果:
持有股票的最大利润或不持有股票的最大利润:max(dp[i] [0] , dp[i] [1])
其实不持有股票的最大利润肯定是比持有股票的利润大,可直接输出dp[i] [1]
class Solution {public int maxProfit(int[] prices) {int[][] dp = new int[prices.length][2];// 初始化、持有股票和不持有股票两种状态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], -prices[i]);// 不持有股票 => 前一天不持有股票或者今天刚好卖出(卖一次,前一天持有的利润+卖出的利润)dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);}// 最后一天不持有股票肯定比持有股票利润多return dp[prices.length-1][1];}
}
打印结果:
Your input:[7,1,5,3,6,4]
Output:5
Expected:5
stdout:dp[i][0] = -1 dp[i][1] = 0dp[i][0] = -1 dp[i][1] = 4dp[i][0] = -1 dp[i][1] = 4dp[i][0] = -1 dp[i][1] = 5dp[i][0] = -1 dp[i][1] = 5
本题是股票买卖动态规划的基础,需好好理解持有股票与不持有股票,当天的利润应是如何获得的。
另外本题的dp数组可以压缩成一维的数组:
dp数组:
递推公式:
max(dp[0], -prices[i]) 前一天持有或前一天买入max(dp[1], dp[0] + prices[i])前一天不持有或前一天卖出(前一天卖出=前一天持有+利润)初始化:
class Solution {public int maxProfit(int[] prices) {int[] dp = new int[2];dp[0] = -prices[0]; // 持有股票dp[1] = 0; // 不持有股票for (int i = 1; i < prices.length; i++) {dp[0] = Math.max(dp[0], -prices[i]);dp[1] = Math.max(dp[1], dp[0] + prices[i]);
// System.out.println("dp[0] = "+dp[0] + "\tdp[1] = " +dp[1]);}return dp[1];}
}
打印结果:
Your input:[7,1,5,3,6,4]
Output:5
Expected:5
stdout:dp[0] = -1 dp[1] = 0dp[0] = -1 dp[1] = 4dp[0] = -1 dp[1] = 4dp[0] = -1 dp[1] = 5dp[0] = -1 dp[1] = 5
贪心: 另外本题还可以直接使用贪心,只需要找到左边最小的数,最右的最大值,即可求得最大利润
class Solution {public int maxProfit(int[] prices) {int min = Integer.MAX_VALUE;int result = 0;for (int i = 0; i < prices.length; i++) {// 从左到右找到最小值min = Math.min(min, prices[i]);// 每次直接比较最大利润区间result = Math.max(result, prices[i] - min);}return result;}
}
贪心的思路前面就做过了,这里主要考虑使用dp的方法。
和1不一样的地方:可以多次买入和卖出!
class Solution {public int maxProfit(int[] prices) {int[][] dp = new int[prices.length][2];// 初始化、持有股票和不持有股票两种状态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]);// System.out.println("dp[i][0] = " + dp[i][0] + "\tdp[i][1] = " + dp[i][1]);}// 最后一天不持有股票肯定比持有股票利润多return dp[prices.length-1][1];}
}
同样,本题也可以写成一维数组的形式:
class Solution {public int maxProfit(int[] prices) {int[] dp = new int[2];dp[0] = -prices[0]; // 持有买票,买入(赊账)dp[1] = 0; // 不持有股票for (int i = 1; i < prices.length; i++) {// 持有 昨天持有或今日卖出(后面有钱了就不用赊账)dp[0] = Math.max(dp[0], dp[1]-prices[i]);// 不持有股票 昨天不持有或今日卖出(今日卖出昨日肯定就持有)dp[1] = Math.max(dp[1], dp[0]+prices[i]);}return dp[1];}
}
买卖股票重点:
今日持有股票的状态:
昨日不持有,今日才买入 => 就看前面是否赚钱
-prices[i],相当于赊账去买dp[1]-prices[i],第一次赊账买,后面用前面持有是赚的钱去买昨日持有 => dp[0]
今天不持有股票状态:
昨日持有,今日卖出 => 都是用昨日持有股票的状态(可能赊账买入),再加上今日卖这张股票赚的钱
dp[0]+prices[i]dp[0]+prices[i]不持有 => dp[1]
下一篇:2023-03-03干活小计