1 | 给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。 |
动态规划
dp[i][0] 的转移方程,如果这一天交易完后手里没有股票,那么可能的转移状态为前一天已经没有股票,即dp[i−1][0],或者前一天结束的时候手里持有一支股票,即dp[i−1][1],这时候我们要将其卖出,并获得prices[i] 的收益,但需要支付fee的手续费。因此为了收益最大化,列出如下的转移方程:
1 | dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee); |
dp[i][1]按状态转移,那么可能的转移状态为前一天已经持有一支股票,即dp[i−1][1],或者前一天结束时还没有股票,即dp[i−1][0],这时候我们要将其买入,并减少prices[i] 的收益。可以列出如下的转移方程:
1 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); |
1 | class Solution { |
方法一中,我们将手续费放在卖出时进行计算。如果我们换一个角度考虑,将手续费放在买入时进行计算,那么就可以得到一种基于贪心的方法。
我们用buy 表示在最大化收益的前提下,如果我们手上拥有一支股票,那么它的最低买入价格是多少。在初始时,buy 的值为 prices[0] 加上手续费 fee。那么当我们遍历到第 i(i>0) 天时:
如果当前的股票价格prices[i] 加上手续费fee小于buy,那么与其使用buy 的价格购买股票,我们不如以 prices[i]+fee 的价格购买股票,因此我们将buy 更新为prices[i]+fee;
如果当前的股票价格prices[i] 大于buy,那么我们直接卖出股票并且获得prices[i]−buy 的收益。但实际上,我们此时卖出股票可能并不是全局最优的(例如下一天股票价格继续上升),因此我们可以提供一个反悔操作,看成当前手上拥有一支买入价格为prices[i] 的股票,将 buy 更新为 prices[i]。这样一来,如果下一天股票价格继续上升,我们会获得 prices[i+1]−prices[i] 的收益,加上这一天prices[i]−buy 的收益,恰好就等于在这一天不进行任何操作,而在下一天卖出股票的收益;
对于其余的情况,prices[i] 落在区间[buy−fee,buy] 内,它的价格没有低到我们放弃手上的股票去选择它,也没有高到我们可以通过卖出获得收益,因此我们不进行任何操作。
上面的贪心思想可以浓缩成一句话,即当我们卖出一支股票时,我们就立即获得了以相同价格并且免除手续费买入一支股票的权利。在遍历完整个数组prices 之后之后,我们就得到了最大的总收益。
1 | class Solution { |
参考文献
1 | 作者:LeetCode-Solution |