1. 关于动规-股票
分成两种状态持有[0]和不持有[1],再拆分两种子情况:
注意理解什么叫“持有”而不是“卖出”
- 在第i天持有 dp[i][0]
- 在第i天买入 =dp[i-1][1]-prices[i]
- 什么是-prices[i]?——目的是找到最小的-price[i],让买入值最低。因为一开始和他比较的值就是price[0]的买入价,而不是0
- 在以前买入 =dp[i-1][0]
- 在第i天买入 =dp[i-1][1]-prices[i]
- 在第i天不持有 dp[i][1]
- 在第i天卖出 =dp[i-1][0]+prices[i]
- 在以前卖出 =dp[i-1][1]
2. 例题
lc123. 买卖股票的最佳时机 III
思路
同上,主要考虑的是0/1状态的改变
情形:股票-考虑持有状态-限制交易次数(状态+1)
- 创建dp:在第i天时,持有股票的最大金额
- 初始化:对买入状态都进行填充
- 注意,不用写第一天不购买的情况!接下来的递推中,可以假设第一天购买了,然后通过比价的方式去把太贵的买入价-prices[0]洗掉
- 递推:当天持有[1.当天买入 2.以前买入] + 当天不持有[1.当天卖出 2.以前卖出]
- 双层递归,统计当遍历到第i天时,其持有情况从1~限制次数(2)的所有情况
- 遍历顺序:递增,每天需要以前一天的情况为基础
代码实现
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][][] dp=new int[len][3][2];
//特殊情况:空值或者只有一天
if(prices==null || prices.length==1){
return 0;
}
//初始化:注意!这里不用写第一天不购买的情况!接下来的递推中,可以假设第一天购买了,然后通过比价的方式去把太贵的买入价-prices[0]洗掉
for(int j=1;j<=2;j++){
dp[0][j][0]=-prices[0];
}
//递推:
for(int i=1;i<prices.length;i++){
for(int j=1;j<=2;j++){
//当天持有:1.当天买入 2.以前买入
dp[i][j][0]=Math.max(dp[i-1][j-1][1]-prices[i],dp[i-1][j][0]);
//当天不持有:1.当天卖出 2.以前卖出
dp[i][j][1]=Math.max(dp[i-1][j][0]+prices[i],dp[i-1][j][1]);
}
}
return Math.max(dp[len-1][2][0],dp[len-1][2][1]);
}
}
lc123. 买卖股票的最佳时机 IV
思路
同上,情形:股票-考虑持有状态-限制交易次数(状态+1)
代码实现
class Solution {
public int maxProfit(int k, int[] prices) {
int len = prices.length;
int[][][] dp=new int[len][k+1][2];
//特殊情况:空值或者只有一天
if(prices==null || prices.length==1){
return 0;
}
//初始化:注意!这里不用写第一天不购买的情况!接下来的递推中,可以假设第一天购买了,然后通过比价的方式去把太贵的买入价-prices[0]洗掉
for(int j=1;j<=k;j++){
dp[0][j][0]=-prices[0]; //问:第一天购买j不是撑死了是1吗?为什么需要把所有的j都填上?
}
//递推:
for(int i=1;i<prices.length;i++){
for(int j=1;j<=k;j++){
//当天持有:1.当天买入 2.以前买入
dp[i][j][0]=Math.max(dp[i-1][j-1][1]-prices[i],dp[i-1][j][0]);
//当天不持有:1.当天卖出 2.以前卖出
dp[i][j][1]=Math.max(dp[i-1][j][0]+prices[i],dp[i-1][j][1]);
}
}
return Math.max(dp[len-1][k][0],dp[len-1][k][1]);
}
}
lc123. 买卖股票的最佳时机含冷冻期
思路
同上,情形:股票-考虑持有状态-有冷冻期(冷冻1天)
其他同上,
初始化考虑要写前两天的情况,而非没有冷冻期时的第一天
递推考虑
- i天持有:
- 今天买 dp[i-2][1]-prices[i]
- 以前买 dp[i-1][0]
- i天不持有:
- 今天卖 dp[i-1][0]+prices[i]
- 以前卖 dp[i-1][1]
代码实现
lass Solution {
public int maxProfit(int[] prices) {
//创建dp
int[][] dp=new int[prices.length][2];
//特殊情况
if(prices==null || prices.length==1) return 0;
//初始化
dp[0][0]=-prices[0];
dp[0][1]=0;
dp[1][0]=Math.max(dp[0][0],-prices[1]);
dp[1][1]=Math.max(dp[0][0] + prices[1], dp[0][1]);
//递推
for(int i=2;i<prices.length;i++){
dp[i][0]=Math.max(dp[i-2][1]-prices[i],dp[i-1][0]);
dp[i][1]=Math.max(dp[i-1][0]+prices[i],dp[i-1][1]);
}
return Math.max(dp[prices.length-1][0],dp[prices.length-1][1]);
}
}