[路飞]_leetcode-714-买卖股票的最佳时机含手续费

简介: leetcode-714-买卖股票的最佳时机含手续费

网络异常,图片无法展示
|


[题目地址][B站地址]


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


dp[i][0] 表示第 i 天不持有股票的利润 dp[i][1] 表示第 i 天持有股票的利润


转移方程


有了状态定义后,我们需要思考的就是如果求得第 i 天的利润


在本题中,当天不持有股票的利润可以根据两种情况求得


  1. 如果前一天不持有股票,那么今天也不持有股票的利润就等于前一天不持有股票的利润
  2. 如果前一天持有股票,俺么今天不持有股票的利润就等于前一天持有股票的利润+当前的价格减去手续费


所以可以推导出状态转移方程如下:


dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]-fee)


当天持有股票的利润同样可以根据两种情况求得


  1. 如果前一天不持有股票,那么今天持有股票的利润就等于前一天不持有股票的利润-今天的价格
  2. 如果前一天持有股票,那么今天持有股票的利润就等于前一天持有股票的利润


所以可以推导状态转移方程如下:


dp[i][1] = Math.max(dp[i-1][0]-prices[i],dp[i-1][1])


解题代码


基于以上基础,第一版代码如下:


var maxProfit = function(prices, fee) {
  const dp = [[0,-prices[0]]];
  // 求得每一天持有股票和不持有股票的利润
  for(let i = 1;i<prices.length;i++){
    dp[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[prices.length-1][0]
};
复制代码


这里要注意的是通常理解,手续费是本次交易金额的一部分,所以最后肯定是把手里的股票卖出利润更高,返回最后一天不持有股票的利润即可。


以上代码提交是可以通过的,但是内存消耗只击败了 40+% 的用户


这里空间复杂度高是因为要在dp数组中创建prices.length个子数组,空间复杂度为 O(2n) = O(n)


本题第 i 天的利润只依赖 i-1 天的利润,所以可以利用滚动数组的技巧来优化空间复杂度


代码如下:


var maxProfit = function(prices, fee) {
  const dp = [[0,-prices[0]],[]];
  // 求得每一天持有股票和不持有股票的利润
  for(let i = 1;i<prices.length;i++){
    const cur = i%2,
    pre = !cur*1;
    dp[cur][0] = Math.max(dp[pre][0],dp[pre][1]+prices[i]-fee)
    dp[cur][1] = Math.max(dp[pre][1],dp[pre][0]-prices[i])
  }
  // 返回最后一天不持有股票的利润
  return dp[(prices.length-1)%2][0]
};
复制代码


这里滚动数组的技巧是利用下标 i%2 的结果不停的更新 dp 数组下标 0、1的数据,达到存储第 i-1 和第 i 天数据的目的


至此我们就完成了 leetcode-714-买卖股票的最佳时机含手续费


如有任何问题或建议,欢迎留言讨论!

相关文章
|
5月前
|
算法 Python
【Leetcode刷题Python】309. 最佳买卖股票时机含冷冻期
解决LeetCode上309题“最佳买卖股票时机含冷冻期”的Python代码示例,利用动态规划方法计算在含有冷冻期约束下的最大利润。
46 1
|
5月前
|
算法 Python
【Leetcode刷题Python】121. 买卖股票的最佳时机
解决LeetCode上121题“买卖股票的最佳时机”的Python代码示例,采用一次遍历的方式寻找最佳买卖时机以获得最大利润。
66 1
|
5月前
|
算法
leetcode188 买卖股票的最佳时机IV
leetcode188 买卖股票的最佳时机IV
70 0
|
5月前
|
算法 Python
【Leetcode刷题Python】714. 买卖股票的最佳时机含手续费
提供了两种解决买卖股票最佳时机含手续费问题的Python实现方法:贪心算法和动态规划算法。
53 0
|
5月前
|
算法 Python
【Leetcode刷题Python】122.买卖股票的最佳时机 II
LeetCode "买卖股票的最佳时机 II" 问题的Python代码实现,采用贪心算法在股票价格上升的每一天买入并卖出,以获得最大利润。
29 0
|
4月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
5月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
65 6
|
5月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
130 2
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
57 1
|
4月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口