题目来源:力扣

题目介绍:

给定一个整数数组 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(N3)O(N^3)O(N3), 而后改进, 时间复杂度将为O(N2)O(N^2)O(N2), 然而提交仍然超时, 直到进一步更改最优子结构, 时间复杂度降为O(N)O(N)O(N), 才通过提交.

接下来, 我们从时间复杂度O(N3)O(N^3)O(N3)的算法开始, 逐一介绍我的思路.

在最初的设计中, 考虑从第k天开始的最优交易方案, 如果我们选择第一笔交易为第i天买入, 第j天卖出, 则如果我们能够计算得到从第j+1天开始的最优方案, 则可以计算得到第k天的最优方案.当时这个思路我感觉很容易就想到了, 但后面也证实它是最低效的. 我们使用S[i]表示从第i天开始最优交易方案下的盈利, 可以得到如下状态转移方程:
S[i]=max{piles[t]−piles[s]−fee+S[t+1],s≤i<t<prices.length}S[i] = max\{piles[t]-piles[s] - fee + S[t+1], s \leq i < t < prices.length\}S[i]=max{piles[t]−piles[s]−fee+S[t+1],s≤i<t<prices.length}

在该问题中, 子问题规模为O(N)O(N)O(N), 每一步的选择规模为O(N2)O(N^2)O(N2), 因此该问题时间复杂度为O(N3)O(N^3)O(N3).具体代码实现如下:

class Solution {public int maxProfit(int[] prices, int fee) {if(prices.length == 1)return 0;int[] S = new int[prices.length+1];//基础情形S[prices.length-1] = 0;S[prices.length-2] = Math.max(0, prices[prices.length-1] - prices[prices.length-2] - fee);for(int i = prices.length-3; i >= 0; i--){//当前可以选择的股票买入与卖出时间组合int max = 0;for(int buy = i; buy < prices.length-1; buy++){for(int sell = buy+1; sell < prices.length; sell++){max = Math.max(max, prices[sell]-prices[buy]- fee + S[sell+1]);}}S[i] = max;}return S[0];}
}

我们重新思考该问题, 对于每一天的股票, 可能包含两种情形, 买入当日股票与不买入当日股票. 此时我们引入两个状态变量, 分别为日期与是否买入当日股票.为了计算从日期i开始,买入日期i股票条件下最大收益, 我们需要分别计算在日期往后的各个日期内卖出该股票的最大收益.

基于该最优子结构, 我们的子问题规模为O(N)O(N)O(N), 每一子问题的选择规模为O(N)O(N)O(N). 因此算法的时间复杂度为O(N2)O(N^2)O(N2).具体代码实现如下:

class Solution {public int maxProfit(int[] prices, int fee) {//状态, 天数, 是否购买该日股票int[][] S = new int[prices.length][2];S[prices.length-1][0] = -prices[prices.length-1];S[prices.length-1][1] = 0;for(int i = prices.length-2; i >= 0; i--){int bestBuy = Integer.MIN_VALUE;//如果我在第i日购入了股票,//则可以在第j日继续持有, //或这在第j日卖掉, 卖掉后可以买入第j日的, 也可以不买for(int j = i+1; j < prices.length; j++){//如果我在当日卖出了股票, 则我可以选择买入当日股票, 或不买入int sell = prices[j] - prices[i] - fee + Math.max(S[j][0], S[j][1]);int donotsell = -prices[i] + S[j][1]; //如果我没卖, 则不能买当日股票bestBuy = Math.max(bestBuy, Math.max(sell, donotsell));}//如果我没有购入第i日的股票//则在第j日, 可以购入股票, 也可以不购入股票int bestNotBuy = Integer.MIN_VALUE;for(int j = i+1; j < prices.length; j++){bestNotBuy = Math.max(bestNotBuy, Math.max(S[j][0], S[j][1]));}S[i][0] = bestBuy;S[i][1] = bestNotBuy;}return Math.max(S[0][0], S[0][1]);}
}

还存在其他最优子结构设计吗? 我一开始是没想到其他更好的方法, 后来看了他人的题解, 才发现真的妙.

我们仍然选择两个状态变量, 一个为日期, 一个表示当前用户是否持有股票. 如果我们需要计期计算日期i时用户持有股票所能获得的最大收益, 我们需要计算在日期i-1时用户持有股票的情形下, 在日期i不售出的收益, 以及在日期i不持有股票的情形下, 在日期i购入股票的收益. 两者的最大值, 即为用户在日期i持有股票的最大收益.类似地, 为了计算用户在日期i不持有股票的收益, 我们需要计算用户在日期i-1不持有股票并且不购买日期i股票的收益以及用户在日期i-1持有股票但在日期i卖出的收益.

此时子问题规模为O(N)O(N)O(N), 每一子问题的选择规模为O(1)O(1)O(1), 因此该算法的时间复杂度为O(N)O(N)O(N)

class Solution {public int maxProfit(int[] prices, int fee) {//状态, 天数, 是否持有当日股票//每天的选择, 持有, 卖出, 继续保持int[][] S = new int[prices.length][2];S[0][0] = -prices[0];S[0][1] = 0;for(int i = 1; i < prices.length; i++){//第i天持有的最佳方案即是前一天持有继续保持, 或前一天不持有, 今日购买S[i][0] = Math.max(S[i-1][0], S[i-1][1] - prices[i]);S[i][1] = Math.max(S[i-1][1], S[i-1][0] + prices[i] - fee);}return S[prices.length-1][1];}
}

用户的最大收益即是在最后一天不持有股票的最大收益, 因为在最后一天买入股票总是会使得总收益降低.

在当前的设计中, 算法的空间复杂度为O(N)O(N)O(N), 但由于当前状态下的最优取值仅依赖于其前一状态的最优取值, 因此我们可以进行状态压缩, 将空间复杂度降至O(1)O(1)O(1).

class Solution {public int maxProfit(int[] prices, int fee) {//状态, 天数, 是否持有当日股票//每天的选择, 持有, 卖出, 继续保持int hold = -prices[0];int donotHold = 0;for(int i = 1; i < prices.length; i++){//第i天持有的最佳方案即是前一天持有继续保持, 或前一天不持有, 今日购买//如果用户在当前买入, 在其在当天卖出的收益肯定小于其在当前不卖出的收益//因此, 如果hold = donotHold-prices[i]//则dontotHold = donotHold//因此我们可以不使用中间变量保存hold未改变时的取值hold = Math.max(hold, donotHold - prices[i]);donotHold = Math.max(donotHold, hold + prices[i] - fee);}return donotHold;}
}

leetcode:买卖股票最佳时机含手续费相关推荐

  1. leetcode买卖股票最佳时机相关问题分析

    买卖股票最佳时机相关问题分析 前言 1.121买卖股票的最佳时机 思路分析 代码及运行结果 2.122买卖股票的最佳时机II 思路分析 代码及运行结果 3.123买卖股票的最佳时机III 思路分析 代 ...

  2. 动态规划 leetcode-714 最佳买卖股票时机含手续费

    1.题目 给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 :非负整数 fee 代表了交易股票的手续费用. 你可以无限次地完成交易,但是你每笔交易都需要付手续费.如果你已经 ...

  3. Python Leetcode买卖股票

    所有股票问题基本都可以使用动态规划进行求解. 本文所使用的动态规划方法均参考一下链接: 买卖股票专题讲解 买卖股票之只能一次交易 # # 一次遍历 # class Solution: # def ma ...

  4. 【LeetCode】买卖股票的最佳时机含手续费 [M](动态规划)

    714. 买卖股票的最佳时机含手续费 - 力扣(LeetCode) 一.题目 给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 :整数 fee 代表了交易股票的手续费用 ...

  5. 【算法】贪心算法:LeetCode 714 买卖股票的最佳时机含手续费 、LeetCode 968 监控二叉树

    LeetCode 714 买卖股票的最佳时机含手续费 (中等) 题目 描述 给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 :整数 fee 代表了交易股票的手续费用. 你 ...

  6. 模拟卷Leetcode【普通】714. 买卖股票的最佳时机含手续费

    714. 买卖股票的最佳时机含手续费 给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 :整数 fee 代表了交易股票的手续费用. 你可以无限次地完成交易,但是你每笔交易都 ...

  7. 【贪心算法】Leetcode 714. 买卖股票的最佳时机含手续费

    [贪心算法]Leetcode 714. 买卖股票的最佳时机含手续费 题目 给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 :整数 fee 代表了交易股票的手续费用. ...

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

    714. 买卖股票的最佳时机含手续费 题目 思路 过一遍,记录第i天是否买入和卖出的最值. 代码 class Solution {public:int maxProfit(vector<int& ...

  9. Leetcode刷题笔记 714. 买卖股票的最佳时机含手续费

    714. 买卖股票的最佳时机含手续费 时间:2020年12月17日 知识点:动态规划 题目链接:https://leetcode-cn.com/problems/best-time-to-buy-an ...

  10. 【LeetCode每日一题】——714.买卖股票的最佳时机含手续费

    文章目录 一[题目类别] 二[题目难度] 三[题目编号] 四[题目描述] 五[题目示例] 六[解题思路] 七[题目提示] 八[时间频度] 九[代码实现] 十[提交结果] 一[题目类别] 贪心算法 二[ ...

最新文章

  1. [leetcode] 108.有序数组转换为二叉搜索树
  2. java 类 加载 初始化_java中类的初始化和加载
  3. 大数据分析常见的9个错误
  4. Danfo.js专题 - Danfo.js与Dnotebook简介与入门
  5. Linux (deepin)网络管理详解
  6. 错误代码warning C4013: ‘sqrt‘ undefined; assuming extern returning int怎么解决?
  7. 【文献翻译】Select-Storage: A New Oracle Design Pattern on Blockchain
  8. 每天一篇论文 323/365 Designing Energy-Efficient Convolutional Neural Networks using Energy-Aware Pruning
  9. 关键链方法和传统关键路径方法的比较
  10. 专访风华高科总裁王金全:锐意进取的改革者
  11. 从蓄水池算法到大数据算法一般性的一点看法
  12. NumPy-创建adarray
  13. [车联网安全自学篇] ATTACK安全之Frida反调试检测
  14. 【C++】类的朋友(friend)
  15. 朱哥黑科技--你必须看,无用的话我吃xiang
  16. 使用Excel替换某一字符后的全部内容
  17. 实验报告一:例2-3mux21a
  18. 2007.08.04 入职华为近2周的感受
  19. BGColor.jsp
  20. WIN10中使用WIN7的照片查看器

热门文章

  1. 第三章-2 MSF扫描漏洞模块
  2. 一起学习荷花定律/金蝉定律和竹子定律
  3. python 网站 批量 投票_python requests 简单实现易班自动登录,批量_文章发布,投票发布,评论,点赞,v2.0...
  4. EXCEL,如何进行查找,单条件和多条件查询
  5. 漫步数学分析二十二——魏尔斯特拉斯测试
  6. semilogx 多条曲线_如何在excel中绘制多条曲线
  7. Python中关于函数的操作
  8. 小米手机打开报告mimu查看程序调试错误locat
  9. elementUI_drawer踩坑_抽屉关闭问题
  10. 这十年,阿里开发者毕玄的日常