题目

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/

DP 模型套路

DP 套路之:暴力递归->傻缓存->DP

DP套路之:暴力递归->傻缓存->DP
1、暴力递归过程:递归就是尝试。此时,你的思维逻辑来源于你的自然智慧、你的递归代码具有现实意义。需要注意的是,在递归的时候,参数设计很重要,参数的个数直接决定了后续优化后dp的时间复杂度。
2、傻缓存过程:带缓存的暴力递归。缓存可以是结构化的dp数组(状态有限的时候),或者是哈希表(状态难以穷举,或者状态太多,即便可以穷举也会超出空间限制),这种记忆化搜索的方法肯定比暴力递归要好得多,避免了重复计算。
给暴力递归加缓存的时候,参数的含义/代码含义已经不重要了,缓存的设计可以脱离题意,因为它只是为了避免重复计算而设计的。因此,即便在这一步已经忘了题意,也不妨碍你仅从代码逻辑上进行改写。
3、dp过程:去分析位置的严格依赖关系,将傻缓存转化成结构化的dp。这个过程更加套路,尤其是当你从从自顶向下的记忆化搜索变成了自底向上的dp时候,直接把你的逻辑结构翻了过来。你要先填base case,再按照依赖顺序逐层填dp表,至此你的dp已经搞定了。
你会惊喜的发现你得到一个所谓的状态转移方程,而对于状态转移方程的直观解释,早已脱离了原始的自然智慧可以得到的递归的含义,它也许很短,也许是一个优美的结论,但它只是看起来优美而已,不具有普遍性和启发性,很难举一反三、一下想到。

关于记忆化搜索与dp之争,它们二者时间复杂度同样的好。只不过记忆化搜索没有分析谁先依赖谁后依赖,你没算过你就递归去算,你算过你就直接从记忆表里拿值返回。而严格表结构的动态规划是,我严格的整理好依赖关系,从这张表的简单位置填到复杂位置,也就是说它比记忆化搜索进一步去梳理了依赖的关系,从简单位置,通过这个依赖关系,算出复杂位置,进而求出所有表的过程。

网上大多数的博客/题解,上来就给你贴一个状态转移方程,然后根据这个状态转移方程去重新编一个故事作为解释,你看了之后觉得挺有道理。但实际上,这个新编的故事是用结论去推原因,所以无论它讲的多么清晰,多么有道理,它都已经脱离了原有的思维轨迹了。然后你就会看到评论区一片苦海,有人说“我知道应该dp但是不知道怎么dp”,“怎么才能想到状态转移方程啊”,“方法很巧但是自己想不出来”之类的,你想,为什么啊?作者已经擦掉了所有的思维轨迹,只留下最后的结论以及中间简单的推理步骤,给你看到的证明都是特别漂亮的样子,然后被认为是外星人留在地球的遗孤,我等凡人只能膜拜。你留下这些结论有什么用呢,你把那些思维过程都写出来不是更加激励后人吗?所以等以后有一天,你成为高手了,请你对新手好一点。。

题解

class Solution {public int maxProfit(int[] prices) {// Solution 0:暴力递归+不合理的参数设计(TLE)
//        return process0(prices, 0, 2, -1, false);// Solution 1:暴力递归+删除方法0中的start参数(TLE)
//        return process1(prices, 0, 2, false);// Solution 2:傻缓存(AC)// 注: 若用HashMap<int[3], Integer>做缓存, TLE
//        int[][][] dp = new int[prices.length + 1][3][2];
//        for (int i = 0; i < dp.length - 1; i++) {//            for (int j = 0; j < dp[0].length; j++) {//                for (int k = 0; k < dp[0][0].length; k++) {//                    dp[i][j][k] = -1;
//                }
//            }
//        }
//        return process2(prices, 0, 2, 0, dp);// Solution 3: DP (AC)int[][][] dp = new int[prices.length + 1][3][2]; // i,count,pendingfor (int i = 0; i < dp.length - 1; i++) {for (int j = 0; j < dp[0].length; j++) {for (int k = 0; k < dp[0][0].length; k++) {dp[i][j][k] = -1;}}}for (int i = prices.length - 1; i >= 0; i--) {for (int pending = 0; pending < 2; pending++) {for (int count = 0; count < 3; count++) {if (pending == 0) {if (count == 0) {dp[i][count][pending] = 0;} else {int p1 = dp[i + 1][count][0];int p2 = -prices[i] + dp[i + 1][count - 1][1];dp[i][count][pending] = Math.max(p1, p2);}} else {int p1 = prices[i] + dp[i + 1][count][0];int p2 = dp[i + 1][count][1];dp[i][count][pending] = Math.max(p1, p2);}}}}return dp[0][2][0];}//    public int process2(int[] prices, int i, int count, int pending, int[][][] dp) { // pending参数含义: 0-false 1-true
//        if (dp[i][count][pending] >= 0) return dp[i][count][pending];
//
//        if (pending == 0) { // 当前交易已关闭
//            if (count == 0) { // 无法开启新交易
//                dp[i][count][pending] = 0;
//                return 0;
//            } else { // 可以开启新交易
//                int p1 = process2(prices, i + 1, count, 0, dp);// 持币观望
//                int p2 = -prices[i] + process2(prices, i + 1, count - 1, 1, dp); // 开启新交易
//                dp[i][count][pending] = Math.max(p1, p2);
//                return dp[i][count][pending];
//            }
//        } else { // 当前交易进行中
//            int p1 = prices[i] + process2(prices, i + 1, count, 0, dp); // 结束当前交易,且i+1表示不立刻买入(立刻买入与持股观望获利相同,还浪费一次交易,没必要)
//            int p2 = process2(prices, i + 1, count, 1, dp); // 持股观望
//
//            dp[i][count][pending] = Math.max(p1, p2);
//            return dp[i][count][pending];
//        }
//    }
//
//    // 卖出是赚到的钱,买入是花费的钱,而非直接计算利润
//    public int process1(int[] prices, int i, int count, boolean pending) {//        if (i == prices.length) return 0;
//
//        if (!pending) { // 当前交易已关闭
//            if (count == 0) { // 无法开启新交易
//                return 0;
//            } else { // 可以开启新交易
//                int p1 = process1(prices, i + 1, count, false);// 持币观望
//                int p2 = -prices[i] + process1(prices, i + 1, count - 1, true); // 开启新交易
//                return Math.max(p1, p2);
//            }
//        } else { // 当前交易进行中
//            int p1 = prices[i] + process1(prices, i + 1, count, false); // 结束当前交易,且i+1表示不立刻买入(立刻买入与持股观望获利相同,还浪费一次交易,没必要)
//            int p2 = process1(prices, i + 1, count, true); // 持股观望
//            return Math.max(p1, p2);
//        }
//    }
//
//    // 从当前位置i开始,已持有股票的买入价格为start,剩余count次交易的情况下,能获得的最大profit
//    public int process0(int[] prices, int i, int count, int start, boolean pending) {//        if (i == prices.length) return 0;
//
//        if (!pending) { // 当前交易已关闭
//            if (count == 0) { // 无法开启新交易
//                return 0;
//            } else { // 可以开启新交易
//                int p1 = process0(prices, i + 1, count, -1, false);// 持币观望
//                int p2 = process0(prices, i + 1, count - 1, prices[i], true); // 开启新交易
//                return Math.max(p1, p2);
//            }
//        } else { // 当前交易进行中
//            int p1 = (prices[i] - start) + process0(prices, i + 1, count, -1, false); // 结束当前交易,且i+1表示不立刻买入(立刻买入与持股观望获利相同,还浪费一次交易,没必要)
//            int p2 = process0(prices, i + 1, count, start, true); // 持股观望
//            return Math.max(p1, p2);
//        }
//    }
}

leetcode 123. Best Time to Buy and Sell Stock III | 123. 买卖股票的最佳时机 III(总结DP 模型套路)相关推荐

  1. 【DP + 卖股票】LeetCode 123. Best Time to Buy and Sell Stock III

    LeetCode 123. Best Time to Buy and Sell Stock III Solution1: 不得不让人感叹算法之精妙啊!!! 参考网址:[1]http://www.cnb ...

  2. LeetCode 123. Best Time to Buy and Sell Stock III--Python解法--动态规划--数学题

    此文首发于我的个人博客:zhang0peter的个人博客 LeetCode题解文章分类:LeetCode题解文章集合 LeetCode 所有题目总结:LeetCode 所有题目总结 题目地址:Best ...

  3. leetcode 714. Best Time to Buy and Sell Stock with Transaction Fee | 714. 买卖股票的佳最时机含手续费(递归->傻缓存->dp)

    题目 https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ 题解 经典的 暴力递归 - ...

  4. 【DP + 卖股票】LeetCode 714. Best Time to Buy and Sell Stock with Transaction Fee

    LeetCode 714. Best Time to Buy and Sell Stock with Transaction Fee Solution1: 参考网址:http://www.cnblog ...

  5. 【DP + 卖股票】LeetCode 309. Best Time to Buy and Sell Stock with Cooldown

    LeetCode 309. Best Time to Buy and Sell Stock with Cooldown Solution1: 比较有难度的一道动态规划题了! 参考网址:http://z ...

  6. 【DP + 卖股票】LeetCode 188. Best Time to Buy and Sell Stock IV

    LeetCode 188. Best Time to Buy and Sell Stock IV Solution1:我的答案 参考链接:http://www.cnblogs.com/grandyan ...

  7. 【贪心 和 DP + 卖股票】LeetCode 122. Best Time to Buy and Sell Stock II

    LeetCode 122. Best Time to Buy and Sell Stock II Solution1:我的答案 贪心和DP傻傻分不清! class Solution { public: ...

  8. 【贪心 和 DP + 卖股票】LeetCode 121. Best Time to Buy and Sell Stock

    LeetCode 121. Best Time to Buy and Sell Stock Solution1:我的答案 动态规划和贪心不要区分的那么明显嘛~~~ class Solution { p ...

  9. [LeetCode]122. Best Time to Buy and Sell Stock II

    [LeetCode]122. Best Time to Buy and Sell Stock II 题目描述 思路 I的后续 将数组分为几个小部分, 划分标准是 [i] < [i - 1](划分 ...

  10. leetcode 309. Best Time to Buy and Sell Stock with Cooldown | 309. 最佳买卖股票时机含冷冻期(动态规划)

    题目 https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ 题解 我知道要dp,但是不知道要怎么dp ...

最新文章

  1. 清华博士接亲被要求现场写代码,网友:真是面向对象编程!
  2. Fragment之底层关键操作函数moveToState
  3. 10分钟!构建支持10万/秒请求的大型网站
  4. html设置标签上下居中,html 标签内部元素上下居中
  5. FE助手 json格式化 reslet client
  6. td之间的间距怎么改_论文的一级标题、二级标题格式怎么弄?
  7. 小程序textarea的行间距_微信小程序组件:textarea多行输入框解读和分析
  8. Scrapy框架(持久化,去重,深度控制,cookie)
  9. 4月12日云栖精选夜读:阿里云黄海宇:窄带高清2.0——让直播更惊艳的魔术
  10. [转载]Git安装以及使用Git 管理个人文档
  11. 利用c语言实现函数信号发生器,基于51单片机函数信号发生器完整论文下载 带源码 原理图...
  12. 计算机与现代社会英语作文,急求英文翻译 随着现代社会的发展,人工智能已经逐步进入了我们的生活。人工智能带给了我们生活无穷的便...
  13. 公网Kamailio 代理 freeswitch 和做 sbc
  14. 有什么软件可以搜JAVA题答案_可以搜简答题答案及解析的软件app或者公众号有吗?...
  15. Deep Learning(深度学习)学习笔记整理
  16. 数字图像处理实验之对比度拉伸
  17. solidworks与matlab接口,CAD软件与Matlab_SimMechanics接口问题研究
  18. ips细胞的应用前景论文和IPS细胞目录
  19. Android OpenGL ES 渲染文本
  20. html格子像素画,HTML_纯手工打造CSS像素画,在cssplay网站看到有一组CSS像素 - phpStudy...

热门文章

  1. ZOJ - 4114 Flipping Game(dp+组合数学)
  2. 蓝桥杯 - 完美的代价(贪心+模拟)
  3. android 手机固定mac,Android之获取手机MAC
  4. Django的主要开发流程(以扩充用户模型为例)
  5. 2013年东北赛B题(数位DP)
  6. golang tcp keepalive实践
  7. 逆向工程核心原理学习笔记(四):检索API方法2-设置断点
  8. 趣谈设计模式 | 代理模式(Proxy):利用代理来控制对象的访问
  9. 数据结构与算法 | 二叉树的实现
  10. 抖音xgorgon0408分析