2020-12-17 买卖股票的最佳时机(含手续费)
题目
题解
动态规划
在每一天结束后,账户有两种股票的持有状态:持有与不持有。我们使用\(dp[i][0]\)表示第\(i+1\)天结束后不持有股票的情况下的当前最大收益,使用\(dp[i][1]\)表示第\(i+1\)天结束后持有股票的情况下的当前最大收益。
- 对于\(dp[i][0]\),即第\(i+1\)天结束后不持有股票,若前一天不持有股票,则
dp[i][0] = dp[i-1][0]
;若前一天持有股票,则表示当天将股票卖出,dp[i][0] = dp[i-1][1]+precise[i]-fee
,二者选其大。
\[dp[i][0] = max(dp[i-1][0], dp[i-1][1]+precise[i]-fee)
\]
- 对于\(dp[i][1]\),即第\(i+1\)天结束后持有股票,若前一天不持有股票,则表示当天买入,
dp[i][1] = dp[i-1][0]-precise[i]
;若前一天持有股票,则dp[i][1] = dp[i-1][1]
,二者选其大。
\[dp[i][1] = max(dp[i-1][1], dp[i-1][0]-precise[i])
\]
在本题中,由于当天的状态只与前一天的状态有关,所以不需要维护\(dp\)这样一个二维数组,而只需使用两个变量\(sell\)与\(buy\)来记录状态即可。
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int sell = 0, buy = -prices[0];
int len = prices.size();
for (int i = 1; i < len; ++i) {
sell = max(sell, buy+prices[i]-fee);
buy = max(buy, sell-prices[i]);
}
return sell;
}
};
贪心法
\(buy\)表示在利益最大的前提下,最低的买入价格+交易费用;初始情况buy = precise[0] + fee
,在向后遍历的过程中可能遇到这几种情况:
buy > precise[i]+fee
:即找到了更低的买入价格,使用precise[i]+fee
替换buy
;buy < precise[i]
:即以当前价格卖出,即使加上手续费仍能盈利,应果断卖出。但是后续可能出现更高的股价,这时可以将buy
置为precise[i]
,若后续出现更高的价格,比如下一天出现更高的价格,则profit += precise[i+1] - precise[i]
;precise[i] + fee > buy > precise[i]
:这种情况既不能卖出,也不能以更低的价格买入,不做操作。
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int profit = 0;
int buy = prices[0] + fee;
int len = prices.size();
for (int i =1; i < len; ++i) {
if (buy > prices[i] + fee) {
buy = prices[i] + fee;
} else {
if (buy < prices[i]) {
profit += prices[i] - buy;
buy = prices[i];
}
}
}
return profit;
}
};
总结
一看到题目就知道是动态规划,使用贪心也有机会解出来,但就是想不出状态转换方程,贪心的一些小细节也拿捏不准,最后还是看了题解才能做出来。
CS专业在读,热爱编程。
专业之外,喜欢阅读,尤爱哲学、金庸、马尔克斯。
专业之外,喜欢阅读,尤爱哲学、金庸、马尔克斯。