0714.买卖股票的最佳时机含手续费(动态规划)


文档摘要

参与本项目 ,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益! 714.买卖股票的最佳时机含手续费 力扣题目链接 给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。 你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。 返回获得利润的最大值。 注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益!

714.买卖股票的最佳时机含手续费

力扣题目链接

给定一个整数数组 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.

注意:

  • 0 < prices.length <= 50000.
  • 0 < prices[i] < 50000.
  • 0 <= fee < 50000.

算法公开课

《代码随想录》算法视频公开课:,相信结合视频再看本篇题解,更有助于大家对本题的理解

思路

本题贪心解法:贪心算法:买卖股票的最佳时机含手续费

性能是:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

本题使用贪心算法并不好理解,也很容易出错,那么我们再来看看使用动规的方法如何解题。

相对于动态规划:122.买卖股票的最佳时机II,本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。

唯一差别在于递推公式部分,所以本篇也就不按照动规五部曲详细讲解了,主要讲解一下递推公式部分。

这里重申一下dp数组的含义:

dp[i][0] 表示第i天持有股票所得最多现金。
dp[i][1] 表示第i天不持有股票所得最多现金

如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来

  • 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
  • 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i]

所以:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);

在来看看如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来

  • 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
  • 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金,注意这里需要有手续费了即:dp[i - 1][0] + prices[i] - fee

所以:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);

本题和动态规划:122.买卖股票的最佳时机II的区别就是这里需要多一个减去手续费的操作

以上分析完毕,C++代码如下:

class Solution { public: int maxProfit(vector<int>& prices, int fee) { int n = prices.size(); vector<vector<int>> dp(n, vector<int>(2, 0)); dp[0][0] -= prices[0]; // 持股票 for (int i = 1; i < n; i++) { dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee); } return max(dp[n - 1][0], dp[n - 1][1]); } };
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

其他语言版本

Java:

/** * 卖出时支付手续费 * @param prices * @param fee * @return */ public int maxProfit(int[] prices, int fee) { int len = prices.length; // 0 : 持股(买入) // 1 : 不持股(售出) // dp 定义第i天持股/不持股 所得最多现金 int[][] dp = new int[len][2]; dp[0][0] = -prices[0]; for (int i = 1; i < len; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]); dp[i][1] = Math.max(dp[i - 1][0] + prices[i] - fee, dp[i - 1][1]); } return Math.max(dp[len - 1][0], dp[len - 1][1]); } /** * 买入时支付手续费 * @param prices * @param fee * @return */ public int maxProfit(int[] prices, int fee) { int len = prices.length; // 0 : 持股(买入) // 1 : 不持股(售出) // dp 定义第i天持股/不持股 所得最多现金 int[][] dp = new int[len][2]; // 考虑买入的时候就支付手续费 dp[0][0] = -prices[0] - fee; for (int i = 1; i < len; 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][0] + prices[i], dp[i - 1][1]); } return Math.max(dp[len - 1][0], dp[len - 1][1]); } // 一维数组优化 class Solution { public int maxProfit(int[] prices, int fee) { int[] dp = new int[2]; dp[0] = -prices[0]; dp[1] = 0; for (int i = 1; i <= prices.length; i++) { dp[0] = Math.max(dp[0], dp[1] - prices[i - 1]); dp[1] = Math.max(dp[1], dp[0] + prices[i - 1] - fee); } return dp[1]; } } ```Java //使用 2*2 array class Solution { public int maxProfit(int[] prices, int fee) { int dp[][] = new int[2][2]; int len = prices.length; //[i][0] = holding the stock //[i][1] = not holding the stock dp[0][0] = -prices[0]; for(int i = 1; i < len; i++){ dp[i % 2][0] = Math.max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]); dp[i % 2][1] = Math.max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i] - fee); } return dp[(len - 1) % 2][1]; } }

python

class Solution: def maxProfit(self, prices: List[int], fee: int) -> int: n = len(prices) dp = [[0] * 2 for _ in range(n)] dp[0][0] = -prices[0] #持股票 for i in range(1, n): dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee) return max(dp[-1][0], dp[-1][1])
class Solution: def maxProfit(self, prices: List[int], fee: int) -> int: # 持有股票手上的最大現金 hold = -prices[0] - fee # 不持有股票手上的最大現金 not_hold = 0 for price in prices[1:]: new_hold = max(hold, not_hold - price - fee) new_not_hold = max(not_hold, hold + price) hold, not_hold = new_hold, new_not_hold return not_hold

Go:

// 买卖股票的最佳时机含手续费 动态规划 // 时间复杂度O(n) 空间复杂度O(n) func maxProfit(prices []int, fee int) int { n := len(prices) dp := make([][2]int, n) dp[0][0] = -prices[0] for i := 1; i < n; i++ { dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee) dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) } return dp[n-1][1] } func max(a, b int) int { if a > b { return a } return b }

Javascript:

const maxProfit = (prices,fee) => { let dp = Array.from(Array(prices.length), () => Array(2).fill(0)); dp[0][0] = 0 - prices[0]; for (let i = 1; i < prices.length; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]); dp[i][1] = Math.max(dp[i - 1][0] + prices[i] - fee, dp[i - 1][1]); } return Math.max(dp[prices.length - 1][0], dp[prices.length - 1][1]); }

TypeScript:

function maxProfit(prices: number[], fee: number): number { /** dp[i][0]:持有股票 dp[i][1]: 不持有 */ const length: number = prices.length; if (length === 0) return 0; const dp: number[][] = new Array(length).fill(0).map(_ => []); dp[0][0] = -prices[0]; dp[0][1] = 0; for (let i = 1; i < length; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]); dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee); } return dp[length - 1][1]; };

C:

#define max(a, b) ((a) > (b) ? (a) : (b)) // dp[i][0] 表示第i天持有股票所省最多现金。 // dp[i][1] 表示第i天不持有股票所得最多现金 int maxProfit(int* prices, int pricesSize, int fee) { int dp[pricesSize][2]; dp[0][0] = -prices[0]; dp[0][1] = 0; for (int i = 1; i < pricesSize; ++i) { dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee); } return dp[pricesSize - 1][1]; }

Rust:

贪心

impl Solution { pub fn max_profit(prices: Vec<i32>, fee: i32) -> i32 { let mut result = 0; let mut min_price = prices[0]; for i in 1..prices.len() { if prices[i] < min_price { min_price = prices[i]; } // if prices[i] >= min_price && prices[i] <= min_price + fee { continue; } if prices[i] > min_price + fee { result += prices[i] - min_price - fee; min_price = prices[i] - fee; } } result } }

动态规划

impl Solution { pub fn max_profit(prices: Vec<i32>, fee: i32) -> i32 { let mut dp = vec![vec![0; 2]; prices.len()]; dp[0][0] = -prices[0]; for (i, &p) in prices.iter().enumerate().skip(1) { dp[i][0] = dp[i - 1][0].max(dp[i - 1][1] - p); dp[i][1] = dp[i - 1][1].max(dp[i - 1][0] + p - fee); } dp[prices.len() - 1][1] } }

动态规划空间优化

impl Solution { pub fn max_profit(prices: Vec<i32>, fee: i32) -> i32 { let (mut low, mut res) = (-prices[0], 0); for p in prices { low = low.max(res - p); res = res.max(p + low - fee); } res } }


发布者: 作者: 转发
评论区 (0)
U