Re: [閒聊] 每日LeetCode

看板Marginalman作者 (みけねこ的鼻屎)時間3年前 (2022/12/23 16:06), 編輯推噓4(400)
留言4則, 4人參與, 3年前最新討論串149/719 (看更多)
※ 引述《pandix (麵包屌)》之銘言: : 309. Best Time to Buy and Sell Stock with Cooldown : 給你股票每天的價錢,每天能買/賣/不動,問你最大收益是多少 : 手上只能拿一份股票,也就是買完不能再買,要等到賣掉才能執行下一次購買 : 賣完的隔天只能執行不動這個選項 : Example 1: : Input: prices = [1,2,3,0,2] : Output: 3 : Explanation: transactions = [buy, sell, cooldown, buy, sell] : Example 2: : Input: prices = [1] : Output: 0 方法一 動態規劃 思路: 1.我們可以把股票每天結算的狀態分成三種: 當天結束時持有股票 當天結束時不持有股票 當天的前一天是股票冷卻期 因為有三種狀態所以我們需要一個大小為 [n][3] 的陣列。 (對於買入股票的收益表示為-prices[i]) 2.每個狀態的狀態轉移方程如下: * 當日結束時持有股票用 dp[i][0] 表示 可能是「前日持有股票且今天不買不賣」或「前日不持有股票且未冷卻,今天買入」 兩者較大值,表示如下: max(dp[i - 1][0], dp[i - 1][2] - prices[i] * 當日結束時不持有股票用 dp[i][1] 表示 可能是「前日不持有股票且今天不買不賣」或「前日持有股票今天賣掉」兩者較大值 dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]) * 當天的前一天是股票冷卻期的最大收益用 dp[i][2] 表示 可能是「前日也是冷卻今天不買不賣」或「前日賣了股票的最大收益」兩者較大值 dp[i][2] = max(dp[i - 1][2], dp[i - 1][1]) 3.根據上面的狀態轉移,我們初始化 dp[0][0](第一天收益) 並完成 dp 的表格。 4.返回dp[n - 1][0](因為手中不留股票的時必定比留股票的收益還高) Java Code: ------------------------------------------ class Solution { public int maxProfit(int[] prices) { int n = prices.length; if (n < 2) { return 0; } int[][] dp = new int[n][3]; dp[0][0] = -prices[0]; for (int i = 1; i < n; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] - prices[i]); dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]); dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1]); } return dp[n - 1][1]; } } ------------------------------------------ 5. 以上的代碼可以進一步優化,觀察之後我們會發現 dp[i][2](冷卻期) 實際上只 可能等於 dp[i - 1][1],因為只有前一天不持有股票(賣出股票)才可能進入冷卻 關係式如下: dp[i][2] = dp[i - 2][1]; //所有用到dp[i][2]的地方都替代之 要得到冷卻期的最大收益我們需要第i-2天的最大收益,避免越界我們初始化d p到第1天將程式碼改寫如下: Java Code: ------------------------------------------ class Solution { public int maxProfit(int[] prices) { int n = prices.length; if (n < 2) { return 0; } int[][] dp = new int[n][2]; dp[0][0] = -prices[0]; dp[1][0] = Math.max(-prices[0], -prices[1]); dp[1][1] = Math.max(0, -prices[0] + prices[1]); for (int i = 2; i < n; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 2][1] - prices[i]); dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]); } return dp[n - 1][1]; } } ------------------------------------------ 空間複雜度 O(3n) => O(2n) 方法二 貪婪演算法 思路: 1.根據上面改良版的dp思路,我們實際上每次計算不需要知道dp[i]到dp[n]的所有結果 ,只會需要前兩個結果所以我們可以把dp矩陣改成變數來儲存,看起來跟對收益做貪婪 演算法有90%像。 Java Code: ------------------------------------------ class Solution { public int maxProfit(int[] prices) { int buy = Integer.MIN_VALUE; int preBuy = 0; int sell = 0; int preSell = 0; for (int price : prices) { preBuy = buy; buy = Math.max(preBuy, preSell - price); // 找出最低買價 preSell = sell; sell = Math.max(preSell, preBuy + price); // 找出最高收益 } return sell; } } ------------------------------------------ 對阿 -- https://i.imgur.com/sjdGOE3.jpg
-- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 122.100.75.86 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Marginalman/M.1671782809.A.314.html

12/23 16:14, 3年前 , 1F
直覺是貪婪 看到DP我都嚇尿了
12/23 16:14, 1F

12/23 16:16, 3年前 , 2F
大師
12/23 16:16, 2F

12/23 16:18, 3年前 , 3F
大師級
12/23 16:18, 3F

12/23 16:42, 3年前 , 4F
大師
12/23 16:42, 4F
文章代碼(AID): #1ZfM6PCK (Marginalman)
討論串 (同標題文章)
文章代碼(AID): #1ZfM6PCK (Marginalman)