關鍵字:leetcode,Best Time To Buy And Sell Stock,算法,algorithm,動態規劃,dynamic programmingjava
leetcode 上關於Best Time to Buy and Sell Stock
主題的題目有四個:算法
這四個題目難度依次遞增。大體意思就是,給咱們一個 List<Integer> prices
,而後讓咱們找到怎麼買賣才能得到最大收益。其中第四個問題是尋求一個通解,在給定 prices
和最大買賣次數k
的狀況下,求最大收益。數組
首先大體的解題方向是動態規劃,這個應該不難想到。以後就是怎麼找到狀態,怎麼列狀態轉移方程。考慮某一天的狀況,能夠有以下三種狀態:ui
由於這個題目咱們要找到最大收益,因此,若是最後一天的狀態是買入的話,那麼其收益必定不是最大的,由於最後一天買入的話,就沒有機會賣出了。那麼,上面的三個狀態能夠減小到兩個:code
因此,咱們用 soldAtToday[k] 來表示當天賣出且賣出的時候交易了 k 手的時候的最大收益,soldNotAtToday[k] 表明在以前某天賣出,且當前交易手數爲 k 的時候的最大收益。那麼,狀態轉移方程就能夠用以下僞代碼描述:ip
soldAtToday[k] = max(soldAtYesterday[k] + price, soldNotAtYesterday[k - 1] + price); soldNotAtToday[k] = max(soldAtYesterday[k], soldNotAtYesterday[k]);
其中,k 是交易次數。須要注意的是soldAtToday[k] = max(soldAtYesterday[k] + price, soldNotAtYesterday[k - 1] + price);
中第一個備選項是soldAtYesterday[k]
,而不是soldAtYesterday[k - 1]
,其含義就是,把本應該昨天賣的延長一天到今天賣,因此交易次數仍是 k 。leetcode
具體實現的時候,咱們發現 soldAtToday 和 soldNotAtToday 都是隻依賴於 soldAtYesterday 和 soldNotAtYesterday,因此咱們能夠利用兩個長度爲 k + 1 的數組來完成 today 和 yesterday 數據的存儲。get
package BestTimeToBuyAndSellStock.VersionIV; @SuppressWarnings("Duplicates") class Solution { private int quickSolve(int[] prices) { int len = prices.length, profit = 0; for (int i = 1; i < len; i++) { // as long as there is a price gap, we gain a profit. if (prices[i] > prices[i - 1]) profit += prices[i] - prices[i - 1]; } return profit; } public int maxProfit(int k, int[] prices) { if (prices == null || prices.length <= 1 || k <= 0) { return 0; } int len = prices.length; if (k >= len / 2) return quickSolve(prices); int today = 1; int yesterday = 0; int[][] soldAt = new int[2][k + 1]; int[][] soldNotAt = new int[2][k + 1]; soldAt[today][0] = 0; soldAt[yesterday][0] = 0; soldNotAt[today][0] = 0; soldNotAt[yesterday][0] = 0; for (int i = 0; i < k + 1; i++) { soldAt[yesterday][i] = 0; soldNotAt[yesterday][i] = 0; } for (int i = 1; i < prices.length; i++) { int price = prices[i] - prices[i - 1]; for (int j = 1; j < k + 1; j++) { soldAt[today][j] = Math.max( soldAt[yesterday][j] + price, soldNotAt[yesterday][j - 1] + price ); soldNotAt[today][j] = Math.max( soldAt[yesterday][j], soldNotAt[yesterday][j] ); } int tmp = yesterday; yesterday = today; today = tmp; } return Math.max(soldAt[yesterday][k], soldNotAt[yesterday][k]); } }
觀察代碼發現,開頭多了一個 quickSolve 。這是由於,若是直接把上面咱們描述的算法實現出來,提交上去,會出現 TimeLimted 的問題。仔細分析了一下超時的用例,發現他們的特徵是 k 很大。其實,當 k 大於 prices.length / 2 的時候,就至關於沒有 k 的限制,即隨便買賣了,由於不考慮當天買當天賣的狀況,或者把當天買賣的收益虛擬的記爲 0 。那麼咱們的算法就退化成最簡單的狀況,因而使用一個 quickSolve 來解決便可。
這個題目也對咱們平常工做提供了啓示:出現問題了,找到瓶頸,分析特徵,而後突破。it