我在思考這個不就是不操作加入到裡面,原本不操作只是為了方便操作,現在則是要考慮進去,如果考慮進去的話,只要下標定義清楚
實際做了之後,發現下標的定義定義為三個狀態
但是遞推公式很難推出來,想法很不清晰。
原來是我的下標定義就錯了,這步錯後面推導就會出現問題
把不持有的兩個狀態進行拆分
已經賣出且過了冷凍期以及賣出股票
在加上第四個冷凍期,冷凍期一定是賣出的後一天
看完之後才比較清晰
這只是買賣股票II在sell時多加一個減去手續費的過程,其餘部分基本相同。
看完之後真的就是跟之前一樣,只在再總結股票問題的部分講的很清晰
定義DP數組以及下標的含意
分為四種狀況
dp[i][0]: 持有股票
dp[i][1]: 保持賣出股票(已過冷凍期)
dp[i][2]: 賣出股票
dp[i][3]: 冷凍期
遞推公式
dp[i][0] 會有兩種角度三種情況
冷凍期
dp[i - 1][3] - prices[i]
保持賣出股票
dp[i - 1][1] - prices[i]
dp[i][1] 保持賣出則是也有兩種狀況
保持持有
dp[i - 1][1]
過了冷凍期
dp[i - 1][3]
dp[i][2] 賣出股票就一種狀態 dp[i - 1][0] + prices[i]
dp[i][3] 冷凍期也只有一個狀態就是賣出後 dp[i - 1][2]
根據遞推公式、題意以及定義,確定DP數組如何初始化
dp[0][0] = -prices[0] 就是一開始的現金
dp[0][1]、dp[0][3] 本身是一個非法狀態,但是套入的推公式,根據需要初始化為0
dp[0][2] 賣出後正負相抵,初始化為0
確定遍歷順序
是透過前面的狀況推導出後面的狀況,所以是由前往後遍歷
class Solution {
public:
int maxProfit(vector& prices) {
vector> dp (prices.size(), vector(4,0)) ;
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); i++) {
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3] - prices[i], dp[i - 1][1] - 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(dp[prices.size() - 1][1], max(dp[prices.size() - 1][2], dp[prices.size() - 1][3]));
}
};
定義DP數組以及下標的含意
分為兩種狀況
dp[i][0] 第i天持有股票的現金
dp[i][1] 第i天不持有股票所得的現金
遞推公式
dp[i][0]
分兩種狀況
我們要瞭解到dp[i][0] 主要是比較昨天持有比較值得還是今天持有該股票會比較值得
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] -price[i] )
也是分兩種狀況
dp[i][1] 可以思考為昨天之前賣掉股票會比較多錢還是今天賣股票會比較多錢
最後再減去手續費
dp[i][1] = max(dp[i - 1][0], price[i] + dp[i - 1][0] - fee)
根據遞推公式、題意以及定義,確定DP數組如何初始化
dp[0][0] 代表第一天持有股票 所以是-price[0]
dp[0][1] 代表第一天還沒有賣出股票所以是 0
確定遍歷順序
是透過前面的狀況推導出後面的狀況,所以是由前往後遍歷
class Solution {
public:
int maxProfit(vector& prices, int fee) {
vector> dp (prices.size(), vector(2));
dp[0][0] = -prices[0];
dp[0][1] = 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];
}
};
單一股票買賣一次求最大数值,主要就是定義上持有股票的現金以及不持有的部分進行初步的劃分
动态规划:121.买卖股票的最佳时机
透過遞規公式找出数組中的最大数值
dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
單一股票買賣多次求最大数值,主要就是定義上持有股票的現金以及不持有的部分進行初步的劃分
动态规划:122.买卖股票的最佳时机II
在遞推公式上就是在買入的時機會出現差異,變成是說上一次獲得的現金,減去當下的股票金額,哪個優
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]);
單一股票只能買賣特定次数
动态规划:123.买卖股票的最佳时机III 、 动态规划:188.买卖股票的最佳时机IV
主要體現在下標上面就會有差異,分為沒有操作、買入股票、賣出股票這三個部分
因為每次的買賣都一定是2 * k 次(買入、賣出),所以在的推公式上其實就是將買賣次数進行抽象化處理
for(int j = 1; j < 2 * k + 1; j++) {
if(j % 2 == 1) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i]);
}
單一股票只能買賣包含冷凍期
动态规划:309.最佳买卖股票时机含冷冻期
主要體現在定義上會有所差別,需要將賣出的狀態分為,保持賣出以及賣出,這樣使得冷凍期的數值有所依歸
遞推公式如下
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3]- prices[i], dp[i - 1][1]- 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];
單一股票多次買賣包含手續費
动态规划:714.买卖股票的最佳时机含手续费
主要體賣出時,需要多加上一個手續費的計算
遞推公式如下
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);
困難點主要是狀態的拆分,買賣股票都有兩種狀態,買入、持續買入、賣出以及持續賣出,在冷凍的題目中如果沒有釐清這點就會出現很大的問題。
主要學了1hr左右,題目比較少
主要是統整買賣股票的問題,以及了解冷凍期的思路
● 今日学习的文章链接和视频链接
视频讲解:动态规划来决定最佳时机,这次有冷冻期!| LeetCode:309.买卖股票的最佳时机含冷冻期_哔哩哔哩_bilibili
https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html
视频讲解:动态规划来决定最佳时机,这次含手续费!| LeetCode:714.买卖股票的最佳时机含手续费_哔哩哔哩_bilibili
https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html
https://programmercarl.com/动态规划-股票问题总结篇.html