题目描述
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
样例
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
算法1
(贪心或单调栈都可以) $O(n)$
维护i之前最小的买入价格,维护在i处卖出的最大收益
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if(n<2) return 0;
int low=prices[0],profit=0;
for(int i=1;i<n;i++)
{
low=min(low,prices[i]);
profit=max(prices[i]-low,profit);
}
return profit;
}
};
算法2
(动态规划-状态机) $O(n)$
1. 状态表示:f[i][0]表示在第i天手里无股票最大收益,f[i][1]表示手里有股票的最大收益
这里只能进行一次交易,所以用户手上不持股所能获得的最大利润,特指卖出股票以后的不持股,
非指没有进行过任何交易的不持股
2. 状态计算:f[i][0]=max(f[i-1][0],f[i-1][1]+prices[i]);
f[i][1]=max(f[i-1][0],-prices[i]);
注意:因为题目只允许一次交易,因此不能加上 dp[i - 1][0],加上的话可能会多次交易
3.边界问题:第0天时持股为f[0][1]=-price[0];
无股为f[0][0]=0;
C++ 代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if(n<2) return 0;
int f[n+1][2];
f[0][0]=0,f[0][1]=-prices[0];
for(int i=1;i<n;i++)
{
f[i][1]=max(f[i-1][1],-prices[i]);
f[i][0]=max(f[i-1][0],f[i-1][1]+prices[i]);
}
return f[n-1][0];
}
};
算法一,说使用单调栈应该是不准确的。单调栈一般用来求解,当前位置左边或者右边第一个大于或者小于他的元素是多少。本题相当于求解当前位置左边最小的元素是多少
错误的,单调栈可以做,每一次维护好以后,栈内元素都小于等于当前元素,这时候,当天的最大收入就等于当日价格-栈底价格
单调栈做法还能优化 直接维护一个最低价格 那么每天的最大收益就出来了
算法1的做法是错误的,没有考虑到进行了多次买卖的情况
看清楚题目