目录
题目链接:121. 买卖股票的最佳时机
思路
①dp数组,采用二维dp数组,分别记录持有和不持有股票时的余额。dp[i][0]表示第i天不持有股票时的余额;dp[i][1]表示第i天持有股票时的余额
②递推公式,dp[i][0] = max(dp[i-1][0], -price[i]);dp[i][1] = max(dp[i-1][1], dp[i-1][0] + price[i])前者表示当前不持有股票,前一天有两种状态,不持有,则余额保持,持有,则买入,减去当前的价格后者表示当前持有股票,前一天也有两种状态,持有,则余额保持,不持有,则今天卖出,加上今天卖出时的价格
③dp数组初始化,dp[0][0] = 0,dp[0][1] = -price[0],第一天不持有,余额0;第一天持有,则表示买入,余额-price[0]
④遍历顺序,由递推公式可知,每天的余额都是前一天的状态推导而来,所以正序遍历
⑤推导dp数组
代码
class Solution {
public:
//持有股票1,未持有股票0
int maxProfit(vector<int>& prices) {
if (prices.size() == 1)
return 0;
vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < prices.size(); i++) {
//今天持有,可能前面买了,也可能今天买
dp[i][1] = max(dp[i - 1][1], -prices[i]);
//今天未持有,可能前面卖了,也可能今天卖
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
}
return dp[prices.size() - 1][0];
}
};
题目链接:122.买卖股票的最佳时机II
思路
①dp数组,采用二维dp数组,分别记录持有和不持有股票时的余额。dp[i][0]表示第i天不持有股票时的余额;dp[i][1]表示第i天持有股票时的余额
②递推公式,dp[i][0] = max(dp[i-1][0], -price[i]);dp[i][1] = max(dp[i-1][1], dp[i-1][0] + price[i])前者表示当前不持有股票,前一天有两种状态,不持有,则余额保持,持有,则买入,减去当前的价格后者表示当前持有股票,前一天也有两种状态,持有,则余额保持,不持有,则今天卖出,加上今天卖出时的价格
③dp数组初始化,dp[0][0] = 0,dp[0][1] = -price[0],第一天不持有,余额0;第一天持有,则表示买入,余额-price[0]
④遍历顺序,由递推公式可知,每天的余额都是前一天的状态推导而来,所以正序遍历
⑤推导dp数组
代码
class Solution {
public:
// 0表示未持有,1表示持有
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len == 1)
return 0;
vector<vector<int>> dp(len, vector<int>(2, 0));
dp[0][0] = 0; // 第一天不买
dp[0][1] = -prices[0]; // 第一天买入
for (int i = 1; i < len; i++) {
// 今天未持有,可能今天卖了;可能前面就卖了或者就没买
dp[i][0] = max(dp[i - 1][1] + prices[i], dp[i - 1][0]);
// 今天持有,可能之前买的,也可能今天买的
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[len - 1][0];
}
};
总结
①利用二维数组进行持有和未持有的状态记录还是很巧妙的,并不是对买入和卖出的状态记录,因为如果股票只能买卖一次时,之前买入后又买了,后面不能进行买卖,无法进行状态记录
②动态规划的核心依然是dp数组的定义以及递推公式,dp数组要能记录所有状态