問(wèn)題:
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:
- You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
- After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]
大意:
你有一個(gè)數(shù)組,第i個(gè)元素表示股票第i天的金額。
設(shè)計(jì)一個(gè)算法來(lái)找到最大收益。你可以隨意交易多次(比如多次買入賣出),但要遵循下面的規(guī)則:
- 你不能同時(shí)做多次操作(也就是賣出之前必須買入)。
- 你賣出股票后,接下來(lái)那一天不能買股票。(需要冷卻一天)
例子:prices = [1, 2, 3, 0, 2]
maxProfit = 3
交易 = [買入, 賣出, 冷卻, 買入, 賣出]
思路:
這是一個(gè)典型的需要?jiǎng)討B(tài)規(guī)劃來(lái)做的題,有三種操作類型:買入(buy)、賣出(sell)、休息(rest)。根據(jù)動(dòng)態(tài)規(guī)劃的方法,我們需要列出三種操作的計(jì)算方程,三個(gè)方程分別表示,以這三種操作作為最后一次操作的情況下的最終最大收益。
根據(jù)定義,我們來(lái)一個(gè)個(gè)看:
買入的前一天必須是休息,最后一天如果要是買入,那最后還需要消耗一筆金錢,這筆金錢是當(dāng)日的股票價(jià)price,那么方程是:
buy[i] = max{rest[i-1]-price, buy[i-1]}
賣出的前一天必須是買入,最后一天賣出后,會(huì)多得到當(dāng)日的股價(jià)price,那么方程是:
sell[i] = max{buy[i-1]+price, sell[i-1]}
休息的話有多種情況,最后一天休息的話,前一天可以是買入、賣出或者休息,且最后一天也不會(huì)有進(jìn)賬或者消費(fèi),那么方程是:
rest[i] = max{buy[i-1], sell[i-1], rest[i-1]}
但是稍微想一下就知道,最后一天買入后的收益一定小于最后一天休息的收益,由小于最后一天賣出的收益,即:
buy[i] <= rest[i] <= sell[i]
那么我們r(jià)est的方程就可以變?yōu)椋?/p>
rest[i] = sell[i-1]
代入buy和sell的方程就是:
buy[i] = max{sell[i-2]-price, buy[i-1]}
sell[i] = max{buy[i-1]+price, sell[i-1]}
由于每次計(jì)算第i個(gè)值時(shí)我們只用到了最多前兩個(gè)sell和前一個(gè)buy,所以我們不需要記錄整個(gè)數(shù)組的buy和sell,將空間復(fù)雜度降低到O(1),只需要記錄前兩個(gè)sell和前一個(gè)buy,根據(jù)代碼的寫法,我們甚至只需要記錄前一個(gè)sell,將對(duì)sell的計(jì)算放在buy之后,那么自然而然就變成前兩個(gè)sell了。
代碼(Java):
public class Solution {
public int maxProfit(int[] prices) {
int sell = 0, prev_sell = 0, buy = Integer.MIN_VALUE, prev_buy;
for (int price : prices) {
prev_buy = buy;
buy = Math.max(prev_sell - price, prev_buy);
prev_sell = sell;
sell = Math.max(prev_buy + price, prev_sell);
}
return sell;
}
}
合集:https://github.com/Cloudox/LeetCode-Record