题目描述:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
一、(leetcode 121)只能买卖一次
代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int buy=INT_MIN;
int sell=0;
for(int p:prices){
buy=max(buy,-p);
sell=max(sell,buy+p);
}
return sell>0?sell:0;
}
};
二、(leetcode 122)允许多次买卖一支股票
代码如下:
法1:
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>>dp(prices.size(),vector<int>(2));
dp[0][0]=-prices[0];//表示买入后的最大利润
dp[0][1]=0;
for(int i=1;i<prices.size();i++){
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
dp[i][1]=max(dp[i-1][1],dp[i][0]+prices[i]);
}
return dp[prices.size()-1][1];
}
};
法2:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res=0;
for(int i=1;i<prices.size();i++){
if(prices[i]>prices[i-1]){
res+=prices[i]-prices[i-1];
}
}
return res;
}
};
三、(leetcode 123)最多可以完成两笔交易
代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int oneBuy=INT_MIN;//第一次买入后的最大利润
int oneSell=0;//第一次卖出后的最大利润
int twoBuy=INT_MIN;//第二次买入后的最大利润
int twoSell=0;//第二次卖出后的最大利润
for(int p:prices){
oneBuy=max(oneBuy,-p);
oneSell=max(oneSell,oneBuy+p);
twoBuy=max(twoBuy,oneSell-p);
twoSell=max(twoSell,twoBuy+p);
}
return twoSell;
}
};
四、(leetcode 188)最多可以完成 k 笔交易
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
if(k==0) return 0;
int n=prices.size();
if(k>=n/2) return greedy(prices);
vector<vector<int>>dp(k,vector<int>(2,INT_MIN));
for(int p:prices){
dp[0][0]=max(dp[0][0],-p);
dp[0][1]=max(dp[0][1],dp[0][0]+p);
for(int i=1;i<k;i++){
dp[i][0]=max(dp[i][0],dp[i-1][1]-p);
dp[i][1]=max(dp[i][1],dp[i][0]+p);
}
}
return dp[k-1][1];
}
int greedy(vector<int>&prices){
int res=0;
for(int i=1;i<prices.size();i++){
if(prices[i]>prices[i-1]){
res+=prices[i]-prices[i-1];
}
}
return res;
}
};
五、(leetcode 901)股票价格跨度
编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。
今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。
例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]。
思路:
利用单调栈;
代码如下:
class StockSpanner {
stack<pair<int,int>>stk;
public:
StockSpanner() {
}
int next(int price) {
if(stk.empty()||price<stk.top().first){
stk.push(pair(price,1));
return 1;
}
int res=1;
while(!stk.empty()&&price>=stk.top().first){
res+=stk.top().second;
stk.pop();
}
stk.push(pair(price,res));
return res;
}
};
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner* obj = new StockSpanner();
* int param_1 = obj->next(price);
*/
六、(leetcode 309)最佳买卖股票时机含冷冻期
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)
代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()==0) return 0;
vector<vector<int>>dp(prices.size(),vector<int>(3));
dp[0][0]=-prices[0];//买入
dp[0][1]=0;//卖出
dp[0][2]=0;//冷冻期
for(int i=1;i<prices.size();i++){
dp[i][0]=max(dp[i-1][0],dp[i-1][2]-prices[i]);//买入
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]);//卖出
dp[i][2]=max(dp[i-1][0],max(dp[i-1][1],dp[i-1][2]));
}
return max(dp[prices.size()-1][1],dp[prices.size()-1][2]);
}
};
七、(leetcode 714)买卖股票的最佳时机含手续费
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
vector<vector<int>>dp(prices.size(),vector<int>(2));
dp[0][0]=-prices[0];
dp[0][1]=0;
for(int i=1;i<prices.size();i++){
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
dp[i][1]=max(dp[i-1][1],dp[i][0]+prices[i]-fee);
}
return dp[prices.size()-1][1];
}
};