题目
给定一个整数数组 prices
,其中 prices[i]
表示第 i
天的股票价格;整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1:
输入: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: 输入:prices = [1,3,7,5,10,3], fee = 3 输出:6
提示:
1 <= prices.length <= 5 * 104 1 <= prices[i] < 5 * 104 0 <= fee < 5 * 104
题解
解题分析
题目描述: 给定每日股票价格的数组,每天可以选择是否买入/卖出,持有时不能再次买入,每笔交易有固定的手续费,求可获得的最大利润。
解题思路:
- 我们可以从题目可以看到,本题是一个典型的动态规划问题。
- 对于动态规划问题我们可以总结一下思路:
- 定义状态转移方程
- 给定转移方程初始值
- 通过代码递推首先转移方程
- 结合本题目我们首先定义转移方程
定义一个二维数组 dp[n][2]:
- dp[i][1] 表示第 i 天不持有可以获得的最大利润;
- dp[i][2] 表示第 i 天持有获得的最大利润(注意是第 i 天持有,而不是第 i 天买入)。
定义转移方程:
- 不持有: dp[i][0] = max(dp[i-1][0], dp[i-1][1] + price[i] - fee)
对于今天不持有,可以从两个状态转移过来,1. 昨天也不持有;2. 昨天持有,今天卖出。获取最大值
- 持有: dp[i][1] = max(dp[i-1][1], dp[i-1][0] - price[i])
对于今天持有, 可以从两个状态转移过来,1. 昨天也持有;昨天不持有,今天买入,获取最大值
- 给转移方程初始化值
对于第 0 天: - 不持有: dp[0][0] = 0; - 持有(即花钱买入):dp[0][1] = -prices[0];
- 代码实现转移方程
class Solution { public int maxProfit(int[] prices, int fee) { int n = prices.length; int[][] dp = new int[n][2]; dp[0][0] = 0; dp[0][1] = -prices[0]; for (int i=0; i< n; 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]); } return dp[n-1][0]; } }
由于我们只需要用到前一次的数据,可以进行空间优化,在转移的时候 dp[i] 从 dp[i-1] 转移而来, 因此可以去掉一维数组。最终解题代码所示。
复杂度分析
- 时间复杂度:O(N)
- 空间复杂度:O(1), 我们没有创建额外的数组来存储。
解题代码
题解代码如下(代码中有详细的注释说明):
class Solution { public int maxProfit(int[] prices, int fee) { int n = prices.length; // sell 表示卖出的最大收益 int sell = 0, buy = -prices[0]; for (int i = 1; i < n; i++) { sell = Math.max(sell, buy + prices[i] - fee); buy = Math.max(buy, sell - prices[i]); } return sell; } }
提交后反馈结果: