题目1:309 买卖股票的最佳时机含冷冻期
题目链接:309 买卖股票的最佳时机含冷冻期
题意
整数数组prices中prices[i]表示第i天的股票价格,可以进行多次交易,但是在卖出股票后,无法在第二天买入股票(冷冻期为1天)算出最大利润
动态规划
动规五部曲
1)确定dp数组及下标i的含义
dp[i][j] 表示第i天持有/不持有股票时收获最大利润
dp[i][0] 表示第i天持有股票时收获最大利润
把不持有股票的状态分成两块
dp[i][1] 表示第i天保持卖出股票时收获最大利润
dp[i][2] 表示具体卖出股票时收获最大利润
dp[i][3] 表示第i天处于冷冻期
2)dp数组初始化
dp[0][0] = -prices[0] 第0天持有股票的状态
dp[0][1] = 0 第0天保持卖出股票的状态无意义,所以根据递推公式
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i],dp[i-1][3]-prices[i])
dp[1][0] = dp[0][1]-prices[1] 第1天持有股票就是在第一天买入股票,dp[1][0]应该为-prices[1]
所以dp[0][1] 应该为 0
dp[0][2] = 0 第0天具体卖出股票 当天买当天卖,此时现金数为0
dp[0][3] = 0 第0天处于冷冻期无意义,所以根据递推公式
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i],dp[i-1][3]-prices[i])
dp[1][0] = dp[0][3]-prices[1] 第1天持有股票 dp[1][0]为-prices[1],那么dp[0][3]应该为0
3)递推公式
第i天持有股票的状态 dp[i][0]
1)一直都持有股票 延续前一天持有股票的状态 ,
2)之前可能会保持不持有股票(买入再卖出收获一定的本金)然后再买入 ,
3)冷冻期当天不可以持有股票,但是冷冻期之后的一天可以持有股票,
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i],dp[i-1][3]-prices[i])
第i天保持卖出股票的状态 dp[i][1]
1)一直都保持卖出股票 保持前一天卖出股票的状态
2)前一天是冷冻期 处于冷冻期的下一天
dp[i][1] = max(dp[i-1][1], dp[i-1][3])
第i天具体卖出股票的状态 dp[i][2]
前一天持有股票,在今天卖出
dp[i][2] = dp[i-1][0] + prices[i]
第i天处于冷冻期
冷冻期的前一天一定是具体卖出股票的状态
dp[i][3] = dp[i-1][2]
4)遍历顺序
根据递推公式,当天状态取决于前一天的状态 从前向后遍历
5)打印dp数组
代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
//定义数组
vector<vector<int>> dp(prices.size(), vector<int>(4, 0));
//dp数组初始化
//持有股票的状态
dp[0][0] = -prices[0];
//保持卖出股票的状态
dp[0][1] = 0;
//具体卖出股票
dp[0][2] = 0;
//冷冻期
dp[0][3] = 0;
for(int i = 1; i <prices.size(); i++){
//持有股票状态 一直持有股票 保持卖出股票的前一天 前一天是冷冻期
dp[i][0] = max(dp[i-1][0], max(dp[i-1][1]-prices[i], dp[i-1][3]-prices[i]));
//保持卖出股票的状态 前一天持有股票当天卖出 前一天是冷冻期状态
dp[i][1] = max(dp[i-1][1], dp[i-1][3]);
//具体卖出股票 前一天持有股票
dp[i][2] = dp[i-1][0] + prices[i];
//冷冻期 前一天具体卖出股票
dp[i][3] = dp[i-1][2];
}
return max(max(dp[prices.size()-1][0], dp[prices.size()-1][1]), max(dp[prices.size()-1][2], dp[prices.size()-1][3]));
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)
题目2:714 买卖股票的最佳时机含手续费
题目链接:714 买卖股票的最佳时机含手续费
题意
整数数组prices中的元素prices[i]表示第i天的股票价格,每次交易股票都需要手续费fee,可以进行多次交易,返回获得的最大利润
动态规划
动规五部曲
1)dp数组及下标i的含义
dp[i][0] 第i天持有股票的最大现金数
dp[i][1] 第i天不持有股票的最大现金数
2)dp数组初始化
第0天持有股票 dp[0][0] = -prices[0]
第0天不持有股票 dp[0][1] = 0
3)递推公式
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]-fee)
4)遍历顺序
根据递推公式 从前向后遍历
5)打印dp数组
代码
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
//定义dp数组
vector<vector<int>> dp(prices.size(), vector<int>(2,0));
//初始化dp数组
//第0天持有股票
dp[0][0] = -prices[0];
//遍历顺序
for(int i=1;i<prices.size();i++){
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]-fee);
}
return dp[prices.size()-1][1];
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)