買賣股票系列
【leetcode】40-best-time-to-buy-and-sell-stock 力扣 121. 買賣股票的最佳時機
【leetcode】41-best-time-to-buy-and-sell-stock-ii 力扣 122. 買賣股票的最佳時機 II
【leetcode】42-best-time-to-buy-and-sell-stock-iii 力扣 123. 買賣股票的最佳時機 III
【leetcode】43-best-time-to-buy-and-sell-stock-iv 力扣 188. 買賣股票的最佳時機 IV
【leetcode】44-best-time-to-buy-and-sell-stock-with-cooldown 力扣 309. 買賣股票的最佳時機包含冷凍期
【leetcode】45-best-time-to-buy-and-sell-stock-with-cooldown 力扣 714. 買賣股票的最佳時機包含手續費
開源地址
為了便於大家學習,所有實現均已開源。歡迎 fork + star~
https://github.com/houbb/leetcode
題目
給定一個整數陣列prices,其中第 prices[i] 表示第 i 天的股票價格 。
設計一個演算法計算出最大利潤。在滿足以下約束條件下,你可以儘可能地完成更多的交易(多次買賣一支股票):
賣出股票後,你無法在第二天買入股票 (即冷凍期為 1 天)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
示例 1:
輸入: prices = [1,2,3,0,2]
輸出: 3
解釋: 對應的交易狀態為: [買入, 賣出, 冷凍期, 買入, 賣出]
示例 2:
輸入: prices = [1]
輸出: 0
提示:
1 <= prices.length <= 5000
0 <= prices[i] <= 1000
v1-DP
整體思路
我們考慮 3 個場景:
// a1: 手上持有股票的最大收益
// a2: 手上不持有股票,並且處於冷凍期中的累計最大收益
// a3: 手上不持有股票,並且不在冷凍期中的累計最大收益
要想計算最大的利潤,只需要考慮不持有股票的對比就可。
至於 a1,是為了中轉計算。
初始化
a1[0] = -prices[0];
遞推公式
a1
a1 什麼時候手上會有股票? 必須是買入的時候。
一種是上次就持有;還有一種處於 a3 狀態,然後買入。
a1[i] = max(a1[i-1], a3[i-1] - prices[i]);
a2
a2: 手上不持有股票,並且處於冷凍期中的累計最大收益
什麼場景會不持有,則處於冷凍期?
就是持有股票,然後直接賣出了?
a2[i] = a1[i-1] + prices[i];
a3
a3: 手上不持有股票,並且不在冷凍期中的累計最大收益
什麼場景不持有股票,且不處於冷凍期。
1)此時不能直接賣出,因為會被冷凍;所以
2)昨天分為兩個場景:a2 狀態;或者 a3 狀態
a3[i] = max(a3[i-1], a2[i-1])
完整的虛擬碼
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
// a1: 手上持有股票的最大收益 主要是為了計算儲存,結果不考慮此場景。
// a2: 手上不持有股票,並且處於冷凍期中的累計最大收益
// a3: 手上不持有股票,並且不在冷凍期中的累計最大收益
int a1[] = new int[n];
int a2[] = new int[n];
int a3[] = new int[n];
// 初始化
a1[0] = -prices[0];
for (int i = 1; i < n; ++i) {
// 持有股票:昨天持有 OR 買入
a1[i] = Math.max(a1[i-1], a3[i-1] - prices[i]);
// 手上不持有股票,並且處於冷凍期中的累計最大收益: 必定是賣出
a2[i] = a1[i-1] + prices[i];
// 手上不持有股票,並且不在冷凍期中的累計最大收益: 昨天可能是 a3; a2
a3[i] = Math.max(a2[i-1], a3[i-1]);
}
// 手裡沒有股票對比即可
return Math.max(a2[n-1], a3[n-1]);
}
}
評價
這一道題嚴格點說還是比較難的,就是我們必須透過 3 個狀態陣列來處理。
所以需要前面題目的鋪墊。