121. 买卖股票的最佳时机
本题实际上就是求最低的价格买入,最高的价格卖出。卖出在买入之前。
①确定dp数组以及下标含义
dp[i][0]:第i天,持有股票的最大现金
dp[i][1]:第i天,不持有股票的最大现金
②确定递推公式
每遍历一个金额,dp[i][0]有两个选择:
1.买入股票 dp[i][0]=-price[i]
2.保持原状 dp[i][0]=dp[i-1][0]
因为买入-price[i]是负数,数字越小绝对值越大,因此取大值可以满足以更少的金额买入。
两个都是负数,每次取两个的大值即可。
dp[i][0]=Math.max(dp[i-1][0],-prices[i])
每遍历一个金额,dp[i][1]有两个选择:
1.卖出股票 dp[i][1]=dp[i-1][0]+price[i] //前一天持有的最大金额-今天的金额数,因为dp[i-1][0]是 负数,因此相加即可。
2.保持原状 dp[i][1]=dp[i-1][1] //不卖出,和上一天保持相同
每次取两个的大值即可。
dp[i][1]=Math.max(prices[i]+dp[i-1][0],dp[i-1][1])
③dp数组如何初始化
dp[0][0]:第一天买入,初始值为-price[0]
dp[0][1]:第一天不能卖出,初始值为0
④确定遍历顺序
dp[i]由前面i-1决定,因此从前向后遍历
⑤举例推导dp数组
public int maxProfit(int[] prices) {
int[][] dp=new int[prices.length][2];
dp[0][0]=-prices[0]; //dp[i][0]:第i天持有股票的最大现金
dp[0][1]=0; //dp[i][1]:第i天卖出股票的最大现金
for(int i=1;i<prices.length;i++){
dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
dp[i][1]=Math.max(prices[i]+dp[i-1][0],dp[i-1][1]);
}
return dp[prices.length-1][1];
}
122. 买卖股票的最佳时机 II
看第一题我觉得还可以能接受,第二题公式勉强可以看懂,但是不知道为什么是这样,怎样想到这样,然后自己推导数组的时候也是完全一头雾水。。真的好难过呜呜呜
本题与上题的区别在于可以多次买入卖出。
dp数组定义与上题相同,区别在于递推公式买入股票。
因为可以多次买入股票,因此当选择买入股票时。
dp[i][0]:第i天,持有股票的最大现金
dp[i][1]:第i天,不持有股票的最大现金
dp[i][0]应为前一天不持有股票的钱数-今天买入股票花费钱数,即dp[i][0]=dp[i-1][1]-price[i]
1.买入股票 dp[i][0]=dp[i-1][1]-price[i]
2.保持原状 dp[i][0]=dp[i-1][0]
因此
dp[i][0]=Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1]与上题相同,卖出时为前一天持有金额+今天的金额
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
public int maxProfit(int[] prices) {
int n = prices.length;
int[][] dp = new int[n][2]; // 创建二维数组存储状态
dp[0][1] = 0; // 初始状态
dp[0][0] = -prices[0];
for (int i = 1; i < n; ++i) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]); // 第 i 天,没有股票
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]); // 第 i 天,持有股票
}
return dp[n - 1][1];
}