1. question: 买卖股票的最佳时机含手续费(中等)
给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee
示例 1:
1 2 3 4 5 6 7 8
| 输入:prices = [1, 3, 2, 8, 4, 9], fee = 2 输出:8 解释:能够达到的最大利润: 在此处买入 prices[0] = 1 在此处卖出 prices[3] = 8 在此处买入 prices[4] = 4 在此处卖出 prices[5] = 9 总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8
|
示例 2:
1 2
| 输入:prices = [1,3,7,5,10,3], fee = 3 输出:6
|
提示:
1 2 3
| 1 <= prices.length <= 5 * 104 1 <= prices[i] < 5 * 104 0 <= fee < 5 * 104
|
2. answers
这道题和买卖股票还是有区别的,因为存在交易费的缘故,所以连续天的收益不再等于单天的收益和。不过,总收益可以认为是若干个子收益之和。
首先一个难点就是如何判断是交易并重新买入,而不是在前面买入的基础上持续持有。
1 2 3 4 5 6 7 8 9
| 从没有交易费的角度来看,[1,8]的利润是等于[1,3]+[3,8]的。如果[4,8]的利润大于[3,8]的话(即[3,4]是负利润),显然[1,8] < [1,3] + [4,8]。
但是存在交易费,要想满足上述条件,[3,4]之间的负利润应该大于交易费,即 [3] - [4] > 交易费。也就是 [4] + 交易费 < [3]。否则因为交易费的缘故,就不如持续持有的利润高。
当满足上述条件时,即进行一次交易。这样才能保证存在交易费的情况下,两段交易优于一段交易
如果不满足条件,即 [4] + 交易费 > [3],这样的话,如果后续遇到比[3]大的值,比如在[10],显然是 [1,10] > [1,3] - 交易费 + [4,10]
如果遇不到比[3]大的,说明后续无论怎么交易,都只能是负利润。
|
所以说,(在已经买入的情况下)如果后续的值小于当前值,并且差值大于交易费,即就应该重新开始一次交易。
那么什么时候买入呢?(在没有买入的情况下)显然如果后面的值小于当前的值,肯定是越低越买入。
那么如何在考虑手续费的同时计算收益呢?在买入的时候要先将手续费加入,只要利润高于花销,那么就卖出(注意,后续还要判断是否真正卖出)。如果没有真正卖出,即等同于买卖股票,连续天的收益等于单天的收益和(因为最开始已经记录了手续费了)。
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class Solution_0109 {
public int maxProfit(int[] prices, int fee) {
int buy = prices[0] + fee;
int sum = 0;
for (int p : prices) {
if (p + fee < buy) { buy = p + fee; } else if (p > buy){
sum += p - buy;
buy = p; } } return sum; }
public static void main(String[] args) { System.out.println();
int[] prices = {1, 3, 2, 8, 4, 9}; int fee = 2;
Solution_0109 s = new Solution_0109();
System.out.println(s.maxProfit(prices, fee)); } }
|
这道题采用贪心的想法,并不容易理解。应该采用动态规划。在做了买卖股票系列题目之后,本题只需要在买入的时候额外减去手续费即可。代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class Solution_0109_04 {
public int maxProfit(int[] prices, int fee) {
int[][] dp = new int[prices.length][2]; dp[0][0] = -prices[0] - fee; dp[0][1] = 0;
for (int i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i] - fee); dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]); }
for (int i = 0; i < prices.length; i++) { for (int j = 0; j < 2; j++) { System.out.print(dp[i][j] + "\t"); } System.out.println(); }
return dp[prices.length - 1][1]; }
public static void main(String[] args) { System.out.println();
Solution_0109_04 s = new Solution_0109_04();
int[] prices = {1,3,7,5,10,3}; int fee = 3;
System.out.println(s.maxProfit(prices, fee)); } }
|
3. 备注
参考力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 (leetcode-cn.com),代码随想录 (programmercarl.com)。