LEETCODE上買賣stock問題彙總解
NO.1
121.Best Time to Buy and Sell Stock
限定只能夠買賣一次。
思路:
因為只能買賣一次,因此我們用兩個變數,buy表示買入價格,profit表示賣出後所賺的差價,buy不斷取陣列中元素的最小值,而profit我們取初始化時profit=0和prices[i]-buy中的最大值。
class Solution { public: int maxProfit(vector<int>& prices) { int buy=INT_MAX; int profit=0; for(int i=0;i<prices.size();i++) { buy=min(buy,prices[i]); profit=max(profit,prices[i]-buy); } return profit; } };
注意,對於之後討論的k次買賣的情形,限定1次買賣當然是一種特殊情況,也可以用通式來進行解決,程式碼如下:
class Solution { public: int maxProfit(vector<int>& prices) { if(prices.empty()) return 0; int T=1; vector<int> status(2*T,INT_MIN); status[0]=-prices[0]; for(int i=1;i<prices.size();i++) { status[0]=max(status[0],-prices[i]); for(int j=1;j<status.size();j++) { status[j]=max(status[j],status[j-1]+prices[i]); } } return max(0,status[2*T-1]); } };
NO.2
122.Best Time to Buy and Sell Stock II
限定可以買賣無限次
其實這題和121題分別是之後通式的兩個特殊情況,這題的特殊在於,買賣k次,但是k>=size/2,換句話說就是無限制次數。
思路:如果後一天的價格高於前一天,那麼會買入,profit+=價格差值,直到遍歷整個陣列
class Solution { public: int maxProfit(vector<int>& prices) { int profit=0; for(int i=1;i<prices.size();i++) profit=max(profit,profit+prices[i]-prices[i-1]); return profit; } };
NO.3
123. Best Time to Buy and Sell Stock III
限定買賣2次
思路:通用解法是從這題中引申而來,因此思路寫的詳細一些。考慮狀態方程的改變,買賣k=2次,那麼狀態總共應該有k*2=4個。
對於0狀態,需要單獨進行賦值處理。之後的1,3代表的是賣出狀態,分別是前一狀態的最大值與當前賣出價格相加和原來此處值兩者間的最大者。2,4為買入,同樣的用dp的思想取最大值。
也即是:
s1 = max(s1, -prices[i]);
s2 = max(s2, s1+prices[i]);
s3 = max(s3, s2-prices[i]);
s4 = max(s4, s3+prices[i]);
那麼我們可以解決這題,程式碼如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.empty())
return 0;
int T=2;
vector<int> status(2*T,INT_MIN);
status[0]=-prices[0];
for(int i=1;i<prices.size();i++)
{
status[0]=max(status[0],-prices[i]);
for(int j=1;j<status.size();j=j+2)
{
status[j]=max(status[j],status[j-1]+prices[i]);
if(j+1<status.size())
status[j+1]=max(status[j+1],status[j]-prices[i]);
}
}
return max(0,status[2*T-1]);
}
};
並且可以得到一般解法。將vector的大小修改為k*2即可,並且按照類似奇偶位置這樣的思想進行處理即可。也就是NO.4中的解法。
NO.4
188. Best Time to Buy and Sell Stock IV
限定最多買賣k次
思路:此時AC會進行報錯,超出限制時長,因此考慮一個輔助函式quick_add,當k>=prices.size()/2時,此時直接進行122題那樣的所有累加即可。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
if(prices.empty() || k<=0)
return 0;
if(k>=prices.size()/2)
return quick_add(prices);
vector<int> status(k*2,INT_MIN);
status[0]=-prices[0];
for(int i=1;i<prices.size();i++)
{
status[0]=max(status[0],-prices[i]);
for(int j=1;j<status.size();j=j+2)
{
status[j]=max(status[j],status[j-1]+prices[i]);
if(j+1<status.size())
status[j+1]=max(status[j+1],status[j]-prices[i]);
}
}
return max(0,status[k*2-1]);
}
private:
int quick_add(vector<int> &prices){
int profit=0;
for(int i=1;i<prices.size();i++)
if(prices[i]>prices[i-1])
profit+=prices[i]-prices[i-1];
return profit;
}
};
---------------------------------------------------------------------------------------------------------------------------------
分割線:上述為止把限定買賣次數的所有情況都考慮了,接下去分別是考慮cooldown和fee的情形
---------------------------------------------------------------------------------------------------------------------------------
NO.5
309. Best Time to Buy and Sell Stock with Cooldown
第i天如果賣出了,第i+1天不能進行買入
思路:
也就是說,考慮在第i天的買入和賣出情況。
賣出sell所得應該是i-1天時買入,第i天賣出的值:buy[i-1]+prices[i];以及第i-1天既沒有賣出也沒有買入的,第i天進行賣出的值:sell[i-1]-prices[i-1]+prices[i](注意sell預設為第i天時已經賣出,因此要先把i-1天賣出的進行減去)兩者之間的最大值。
買入buy應該是第i-2天賣出了,i-1天為cooldown時間情況下的值:sell[i-2]-prices[i];以及第i-1天沒有買入(未進行操作),第i天進行買入情況下的值:buy[i-1]+prices[i-1]-prices[i]兩者之間的最大值。
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()<2)
return 0;
int res=0;
vector<int> sell(prices.size(),INT_MIN);
vector<int> buy(prices.size(),INT_MIN);
sell[0]=0;
buy[0]=-prices[0];
for(int i=1;i<prices.size();i++)
{
sell[i]=max(sell[i-1]-prices[i-1]+prices[i],buy[i-1]+prices[i]);
if(res<sell[i])
res=sell[i];
if(i==1)
buy[i]=max(buy[i-1]+prices[i-1]-prices[i],buy[i]);
else
buy[i]=max(buy[i-1]+prices[i-1]-prices[i],sell[i-2]-prices[i]);
}
return res;
}
};
N0.6
714. Best Time to Buy and Sell Stock with Transaction Fee
思路:也就是說,對於第i天,我們有buy操作或者sell操作,或者什麼都不做。用buy來代表第i天如果買入了後的profit,用sell表示第i天如果賣出了後的profit。
那麼在第i天:
1.我們可以buy或者什麼都不做,即buy[i] = Math.max(buy[i - 1], sell[i - 1] - prices[i]);
2.我們可以賣出或者什麼都不做,即sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
考慮在sell的時候收取手續費
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int size=prices.size();
if(size<=1)
return 0;
vector<int> dp_buy(size,0);
vector<int> dp_sell(size,0);
dp_buy[0]=-prices[0];
for(int i=1;i<prices.size();i++)
{
dp_buy[i]=max(dp_buy[i-1],dp_sell[i-1]-prices[i]);
dp_sell[i]=max(dp_sell[i-1],dp_buy[i-1]+prices[i]-fee);
}
return dp_sell[size-1];
}
};
考慮在buy的時候收取手續費
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int size=prices.size();
if(size<=1)
return 0;
vector<int> dp_buy(size,0);
vector<int> dp_sell(size,0);
dp_buy[0]=-prices[0]-fee;
for(int i=1;i<prices.size();i++)
{
dp_buy[i]=max(dp_buy[i-1],dp_sell[i-1]-prices[i]-fee);
dp_sell[i]=max(dp_sell[i-1],dp_buy[i-1]+prices[i]);
}
return dp_sell[size-1];
}
};
總算寫完了。。。