题解:https://segmentfault.com/a/1190000006672807
121. Best Time to Buy and Sell Stock
求一个数列中的最小值和最大值,要求最小值要在最大值之前
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size()<=1) return 0;
int res=0;
int low=prices[0];
for (int i=1;i<prices.size();i++) {
if (prices[i]>low)
res=max(res,prices[i]-low);
else low=prices[i];
}
return res;
}
};
122. Best Time to Buy and Sell Stock II
https://blog.csdn.net/musechipin/article/details/70858483
309. Best Time to Buy and Sell Stock with Cooldown
这道题可以用状态转移的方法做,上面的网页讲的很清楚,有一点可以优化:当天的买卖状态只与前一天有关,因此可以使用O(1)的空间复杂度。
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size()<=1) return 0;
vector<int> hold;//第i天持有股票的的最大收益
vector<int> unhold;//第i天不持有(已经过了冷却时间)的最大收益
vector<int> cold;//第i天在冷却期 (说明第i-1天是hold)的最大收益
hold.push_back(-prices[0]);
unhold.push_back(0);
cold.push_back(0);
for (int i=1;i<prices.size();i++) {
hold.push_back(max(hold[i-1],unhold[i-1]-prices[i]));
unhold.push_back(max(unhold[i-1],cold[i-1]));
cold.push_back(hold[i-1]+prices[i]);
}
int n=prices.size()-1;
return max(hold[n],max(unhold[n],cold[n]));
}
};
123. Best Time to Buy and Sell Stock III
相当于找两个没有交叉的最大差值区间。使用双向动态规划可以降低时间复杂度,从左到右相当于第一个段时间(0..i)内得到的最大差值,从右向左算一遍相当于第二段时间(i..n)内的最大差值,找到一个i,使得两边之和最大即可。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if (n<=1) return 0;
vector<int> left(n,0);
vector<int> right(n,0);
int min1=prices[0];
left[0]=0;//表示从头到i交易一次所能得到的最大收益
for (int i=1;i<n;i++) {
min1=min(min1,prices[i]);//先求最小值
left[i]=max(left[i-1],prices[i]-min1);//即使后边部分小于0,前一天的盈利也可累积
}
int max1=prices[n-1];
right[n-1]=0;//表示从i到尾交易一次所能得到的最大收益
for (int i=n-2;i>=0;i--) {
max1=max(max1,prices[i]);
right[i]=max(max1-prices[i],right[i+1]);
}
int sum=0;
for (int i=0;i<n;i++)
sum=max(sum,right[i]+left[i]);
return sum;
}
};
393. 买卖股票的最佳时机 IV
还是利用状态转移,但是要注意一次买入卖出算一次交易。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n=prices.size();
if (n<=1) return 0;
if (k>=n/2) {//如果k次数足够多,退化成任意次数买卖的情况
int profit=0;
for (int i=1;i<n;i++)
profit+=max((prices[i]-prices[i-1]),0);
return profit;
}
vector<vector<int>> hold(n,vector<int>(k+1,0));//第i天,交易j次,且持有股票的最大盈利
vector<vector<int>> unhold(n,vector<int>(k+1,0));//第i天,交易j次,且不持有股票的最大盈利
for (int i=0;i<n;i++)
{
for (int j=1; j<=k; j++) {
if (i==0) hold[i][j]=-prices[i];
else {
hold[i][j]=max(unhold[i-1][j-1]-prices[i],hold[i-1][j]);
unhold[i][j]=max(hold[i-1][j]+prices[i],unhold[i-1][j]);
//注意这里是hold[i-1][j],不是hold[i-1][j-1],因为买入再卖出才算一次,j在买入时+1
}
}
}
return unhold[n-1][k];//卖出才有钱
}
};