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];
}
};
总算写完了。。。