买卖股票的最佳时期II(冷冻期)--Leetcode309
问题描述
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
思路描述
此题符合动态规划的特点,每一步的选取受其他位置影响,利用动态规划的思想这题不但可以更好地解决,也可以为这类题目提供了一个解决方案。具体思路如下:
(1) 只需要定义两个数组hold[n],sell[n](n表示问题的规模),前者表示第i天手里还持有股票所能获得的最大利润,后者表示第i天手里没有股票所能获得的最大利润
(2) 以示例举例来看,有hold和sell两个数组,hold[0]表示第一天手里有股票的最大利润,显然,此时只能买入才能有股票,因此hold[0] = -prices[0],同时,第一天不可能就卖出股票,因此sell[0] = 0。到了第二天,hold[1]想要有股票,要不就是维持hold[0]的股票,要不就是看当前股票价格是否更低(能否获得更大利润),所以hold[1] = max(hold[0],-prices[1]),这里-prices[1]是因为之前并没有卖出去股票,只能买入,利润当然为负。sell[1]表示当天没有股票,只有两种情况,要不前一天本身就没有股票并且当天也没买,要不就是之前有股票并且今天卖出去了,因此综合下来得出sell[1] = max(sell[0],hold[0]+prices[1]),后面的过程以此类推
(3) 上述过程可以得到dp的转移方程,如下:
第i天持有股票 hold[i] = max(hold[i-1],sell[i-2]-prices[i])
第i天不持有股票 sell[i] = max(sell[i-1],hold[i-1]+prices[i])
(4) 在编程实现转移方程需要注意初始条件,因为方程里有i-1,i-2这两种状态,所以应该要对初始条件进行判断,也就是(2)里面说的过程
C++实现本题的dp解法
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()<2) return 0;
int len = prices.size();
vector<int> sell(len,0);
vector<int> hold(len,0);
hold[0] = 0-prices[0];
for(int i=1;i<prices.size();i++){
if(i-2>=0) hold[i] = max(hold[i-1],sell[i-2]-prices[i]);
else hold[i] = max(hold[i-1],-prices[i]);
sell[i] = max(sell[i-1],hold[i-1]+prices[i]);
}
return sell[len-1];
}
};
本题dp解法的优化解
从dp解法中应该注意到了第i天的利润只需要i-1和i-2的状态即可,而不需要前面所有的状态,也就是说可以把空间复杂度从o(n)降到o(1),维护前面两个状态即可实现该解法
常数空间的解法
class Solution {
public:
int maxProfit(vector<int>& prices) {
int hold = INT_MIN, pre_hold = 0, sell = 0, pre_sell = 0;
for (int price : prices) {
pre_hold = hold;
hold = max(pre_sell - price, pre_hold);
pre_sell = sell;
sell = max(pre_hold + price, pre_sell);
}
return sell;
}
};