此专栏文章是对力扣上算法题目各种方法总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解.

目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容).

关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接.

想进大厂, 刷算法是必不可少的, 欢迎和博主一起打卡刷力扣算法, 博主同步更新了算法视频讲解 和 其他文章/导图讲解, 更易于理解, 欢迎来看!

关注博主获得题解更新的最新消息!!!

文章目录

  • 0.导图整理
  • 1.dp数组的构建
  • 2.确定递推公式
  • 3.dp数组初始化
  • 4.最终返回结果
  • 5.几个重要的注意点
    • 5.1 k的正序和倒序
    • 5.2 k的范围
    • 5.3 have数组的维数
    • 5.4 Integer.MIN_VALUE / 2
    • 5.5 j的循环
  • 源码
    • Python:
    • java:

题目链接: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/solution/si-wei-dao-tu-zheng-li-dpshu-zu-gou-jian-e97c/

0.导图整理

1.dp数组的构建

本题在形式上似乎是 股票III最多买卖两次 的进阶版, 但其实本题是所有股票问题的通解问题, 其他的股票问题只是在k的取值上有所不同, 但它们的思想都可以用本题的思想来解决, 之后也会单独写一篇文章来总结所有的股票问题.

对于dp数组的定义, 我们首先要确定一共有多少个状态, 通过前面几道题目的训练, 我们可以确定的状态有: 当天的天数i, 当天是否持有股票. 但本题的特殊之处在于: 我们必须还要确定当前进行了几笔交易j, 因为前面的几道题中, k要么是1, 要么是正无穷, 所以我们也不需要将它单独作为一个状态, 但本题就不同了, k可以取任意的值, 所以它也必须作为一个状态.

所以本题必须用3个状态才能完整表示dp数组, 也就是三维dp数组, 按照我们之前说过的方法, 可以通过命名来优化一个状态, 也就是have表示持有状态, no表示不持有状态(我觉得这样的命名比官方的buy, sell更明确), 所以最终的dp数组就是二维dp数组:

  • have[i][j]表示进行恰好 j 笔交易, 并且当前手上持有一支股票, 这种情况下的最大利润.
  • no[i][j] 表示进行恰好 j 笔交易, 并且当前手上不持有股票, 这种情况下的最大利润.

这里我们必须还要明确一个概念: k何时进行变化. 这点很重要, 直接就导致之后递推公式的不同. 官方题解是默认一买一卖才算完整交易一次, 买入不算交易, 卖出才算一次交易, 所以只有卖出时k变化. 当然也有人定义的是买入时k变化, 这种就会产生不同的递推公式, 但都是正确的.

2.确定递推公式

定义出了dp数组之后, 按照前面几题的经验, 递推公式就没太大难度了, 还是每种状态都由两种情况组合而来, 最终取最大值:

根据上面我们定义的k何时变化, 体现在递推公式中就是在推导no[i][j]的第二种情况时用到的have[i-1][j-1], 因为卖出股票时k会变化, 所以上一个持有股票的状态就是k-1了. 这点一定要注意, 它不止在递推公式中很重要, 也在之后的空间优化时很重要!

3.dp数组初始化

本题的初始化过程还是有点复杂的, 但是并不难理解, 这里就不多解释了:

4.最终返回结果

由于在所有的 n 天结束后, 手上不持有股票对应的最大利润一定是严格大于手上持有股票对应的最大利润的, 然而完成的交易数并不是越多越好(例如数组prices 单调递减,我们不进行任何交易才是最优的), 因此最终的答案即为no[n−1][0…k]中的最大值.

5.几个重要的注意点

5.1 k的正序和倒序

本题为了避免状态压缩造成的数据覆盖, 应该采用k倒序才对. 它的解释如下: 最后一行计算no[j](no[i][j])时所用的have[j-1], 本应为have[i-1][j-1]。然而由于采用了状态压缩, i不变, j的前一个循环刚刚计算了have[i][j-1]赋值给了have[j-1], 所以have[j-1]实际为have[i][j-1], 与转移方程产生了偏差.

这是需要采用倒序的原因, 但是本题采用正序也是可以得到相同的结果的, 官方对此也进行了解释, 当然也有人专门写了文章进行推理说明, 导图中也放了相应的链接, 感兴趣的可以去看看, 过程还是挺复杂的.

但是从实际来说, 将k进行倒序, 在代码上是非常容易实现的操作, 只有在j的遍历范围上有一点改动, 其他是完全一样的, 所以我们还是尽可能用倒序遍历保证安全性, 毕竟本题没有影响, 不代表其他动态规划的题目也没有影响, 而且这么容易实现的操作, 根本没什么成本代价可言!

5.2 k的范围

如果交易次数大于n/2, 必然存在有一天交易了两次, 然而这是毫无意义的, 因为 n 天最多只能进行⌊n/2⌋ 笔交易, 其中⌊x⌋ 表示对x向下取整。因此我们可以将 k 对⌊n/2⌋ 取较小值之后再进行动态规划.

5.3 have数组的维数

k+1维是没问题的, 如果维数只有k, 就表示不了交易0次了, 要是数组一直是递减的, 一交易就是亏损.

5.4 Integer.MIN_VALUE / 2

在这是在java中可能遇到的问题, 因为在之后的操作中可能会减去prices[i], 这样就可能导致Integer.MIN_VALUE越界翻转, 所以这里进行了除以2的操作, 在python中是不用担心这个问题的.

5.5 j的循环

no[i][j]的状态转移方程中包含have[i−1][j−1], 在j=0 时其表示不合法的状态, 因此在 j=0 时, 我们无需对 no[i][j] 进行转移, 让其保持值为 0 即可, 所以在j=0时, 我们需要单独对have[i][0]进行处理.

源码

Python:

## 未进行空间优化
class Solution:def maxProfit(self, k: int, prices: List[int]) -> int:if not prices:return 0n = len(prices)k = min(k, n // 2)  # k最大为总天数的一半have = [[0] * (k + 1) for _ in range(n)]no = [[0] * (k + 1) for _ in range(n)]have[0][0], no[0][0] = -prices[0], 0for i in range(1, k + 1): # 不合法状态have[0][i] = no[0][i] = float("-inf")for i in range(1, n): # j=0时, no[i][0]不合法have[i][0] = max(have[i - 1][0], no[i - 1][0] - prices[i])for j in range(1, k + 1):have[i][j] = max(have[i - 1][j], no[i - 1][j] - prices[i])no[i][j] = max(no[i - 1][j], have[i - 1][j - 1] + prices[i]);  return max(no[n - 1])## 进行空间优化
class Solution:def maxProfit(self, k: int, prices: List[int]) -> int:if not prices:return 0n = len(prices)k = min(k, n // 2)  # k最大为总天数的一半have = [0] * (k + 1)no = [0] * (k + 1)have[0], no[0] = -prices[0], 0for i in range(1, k + 1): # 不合法状态have[i] = no[i] = float("-inf")for i in range(1, n): # j=0时, no[0]不合法have[0] = max(have[0], no[0] - prices[i])for j in range(k, 0, -1): # 优化空间, k倒序have[j] = max(have[j], no[j] - prices[i])no[j] = max(no[j], have[j - 1] + prices[i]); return max(no)

java:

// 未进行空间优化
class Solution {public int maxProfit(int k, int[] prices) {if (prices.length == 0) {return 0;}int n = prices.length;k = Math.min(k, n / 2);  // k最大为总天数的一半int[][] have = new int[n][k + 1];int[][] no = new int[n][k + 1];have[0][0] = -prices[0];no[0][0] = 0;for (int i = 1; i <= k; ++i) { // 不合法状态,/2防止越界翻转have[0][i] = no[0][i] = Integer.MIN_VALUE / 2;}for (int i = 1; i < n; ++i) { // j=0时, no[i][0]不合法have[i][0] = Math.max(have[i - 1][0], no[i - 1][0] - prices[i]);for (int j = 1; j <= k; ++j) {have[i][j] = Math.max(have[i - 1][j], no[i - 1][j] - prices[i]);no[i][j] = Math.max(no[i - 1][j], have[i - 1][j - 1] + prices[i]);   }}return Arrays.stream(no[n - 1]).max().getAsInt();}
}

我的更多精彩文章链接, 欢迎查看

各种电脑/软件/生活/音乐/动漫/电影技巧汇总(你肯定能够找到你需要的使用技巧)

力扣算法刷题 根据思维导图整理笔记快速记忆算法重点内容(欢迎和博主一起打卡刷题哦)

计算机专业知识 思维导图整理

最值得收藏的 Python 全部知识点思维导图整理, 附带常用代码/方法/库/数据结构/常见错误/经典思想(持续更新中)

最值得收藏的 C++ 全部知识点思维导图整理(清华大学郑莉版), 东南大学软件工程初试906科目

最值得收藏的 计算机网络 全部知识点思维导图整理(王道考研), 附带经典5层结构中英对照和框架简介

最值得收藏的 算法分析与设计 全部知识点思维导图整理(北大慕课课程)

最值得收藏的 数据结构 全部知识点思维导图整理(王道考研), 附带经典题型整理

最值得收藏的 人工智能导论 全部知识点思维导图整理(王万良慕课课程)

最值得收藏的 数值分析 全部知识点思维导图整理(东北大学慕课课程)

最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程)

红黑树 一张导图解决红黑树全部插入和删除问题 包含详细操作原理 情况对比

各种常见排序算法的时间/空间复杂度 是否稳定 算法选取的情况 改进 思维导图整理

人工智能课件 算法分析课件 Python课件 数值分析课件 机器学习课件 图像处理课件

考研相关科目 知识点 思维导图整理

考研经验–东南大学软件学院软件工程(这些基础课和专业课的各种坑和复习技巧你应该知道)

东南大学 软件工程 906 数据结构 C++ 历年真题 思维导图整理

东南大学 软件工程 复试3门科目历年真题 思维导图整理

最值得收藏的 考研高等数学 全部知识点思维导图整理(张宇, 汤家凤), 附做题技巧/易错点/知识点整理

最值得收藏的 考研线性代数 全部知识点思维导图整理(张宇, 汤家凤), 附带惯用思维/做题技巧/易错点整理

高等数学 中值定理 一张思维导图解决中值定理所有题型

考研思修 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研近代史 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研马原 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研数学课程笔记 考研英语课程笔记 考研英语单词词根词缀记忆 考研政治课程笔记

Python相关技术 知识点 思维导图整理

Numpy常见用法全部OneNote笔记 全部笔记思维导图整理

Pandas常见用法全部OneNote笔记 全部笔记思维导图整理

Matplotlib常见用法全部OneNote笔记 全部笔记思维导图整理

PyTorch常见用法全部OneNote笔记 全部笔记思维导图整理

Scikit-Learn常见用法全部OneNote笔记 全部笔记思维导图整理

Java相关技术/ssm框架全部笔记

Spring springmvc Mybatis jsp

科技相关 小米手机

小米 红米 历代手机型号大全 发布时间 发布价格

常见手机品牌的各种系列划分及其特点

历代CPU和GPU的性能情况和常见后缀的含义 思维导图整理

❤️思维导图整理大厂面试高频数组20: 股票问题IV的dp数组构建和几个重要注意点❤️相关推荐

  1. 思维导图整理大厂面试高频数组23: 股票问题大总结, 彻底搞懂股票问题

    此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...

  2. ❤️思维导图整理大厂面试高频数组: 两万字详解各种数组求和(建议收藏)❤️

    此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...

  3. ❤️思维导图整理大厂面试高频数组19: 股票问题III的dp数组构建/初始化和空间优化难点, 力扣123❤️

    此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...

  4. 思维导图整理大厂面试高频数组补充1: 最接近的三数之和 和 三数之和 的两个不同之处, 力扣16

    此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...

  5. ❤️思维导图整理大厂面试高频数组14: 最大子序积 和 最大子序和 的不同之处, 力扣152❤️

    此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), ...

  6. 最值得收藏的 C++ 清华大学郑莉版全部知识点思维导图整理, 东南大学软件工程初试906科目

    本文的思维导图根据清华大学郑莉出版的C++书籍整理而来并标记出重点内容,适用于想考东南大学软件工程906的同学 思维导图源文件已经发布在我的资源当中, 点击获取全部导图和配套OneNote笔记, 有需 ...

  7. Java基础编程及思维导图整理

    我把Java基础编程及思维导图整理的超级详细,小白都能看懂 Java基础编程及其思维导图 目录: Java学习导图 一.Java基本语法 1.关键字与标识符 2.变量分类 3.运算符 4.流程控制 二 ...

  8. 最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程)(持续更新中)

    本文的思维导图根据慕课上的武汉大学数字图像处理国家精品课程整理而来并标记出重点内容 思维导图就整理了这么多,之后应该也不会更新此内容了, 有需要的可以去 我的主页 了解更多学科的精品思维导图整理 本文 ...

  9. 最值得收藏的 数据结构 全部知识点思维导图整理(王道考研), 附带经典题型整理

    本文的思维导图根据王道的数据结构书本整理而来并标记出重点内容,包括了知识点和部分课后习题 思维导图源文件已经发布在我的资源当中, 点击获取全部导图和配套OneNote笔记, 有需要的可以去 我的主页 ...

最新文章

  1. 003_Spring使用Slf4j和logback日志
  2. 2020-11-22(工作集与常驻集)
  3. RESTful---SpringMVC学习笔记(十三)
  4. Java(ArrayList和LinkedList)、(HashTable与HashMap)、(HashMap、Hashtable、LinkedHashMap和TreeMap比较)
  5. python loads_python dumps和loads区别详解
  6. 属于服务器端运行的程序_生信分析云平台产品开发 - 5 生信分析pipeline服务器端运行...
  7. 专访OPPO Find X5产品经理:深耕自研芯片 以最高标准打造极致旗舰体验
  8. oracle的sqlload遇到超长,oracle sqlload
  9. 值传递和引用传递_C++ 中的值传递和引用传递
  10. matlab点在直线上运动,求助如何用matlab取出直线上的点
  11. 交通流理论学习(Introduciton)
  12. CAS单点登录及处理流程介绍(一)
  13. Java-RPC通信--HSF框架
  14. 程序员 写作_如何经常写作可以使您成为更好的程序员
  15. LeetCode_回文数(三种解法-Java)
  16. 对于时间管理初识--时间管理入门
  17. RTX 4070TI和RTX 4090性能差距 RTX4070ti和4070区别对比
  18. Java快速开发框架_若依——Ruoyi-SpringCloud版本-2.安装redis服务端和客户端-win7
  19. Centos7安装docker并更改阿里云下载镜像地址(附带windows10安装docker教程)
  20. “隔代教育的成功之道”-新浪教育专家宋少卫做客西单图书大厦

热门文章

  1. Hadoop发行版 Cloudera CDH 6.3.2及CM 安装包下载(阿里云盘 不限速)
  2. PC低迷英特尔并购求脱困 win7受累恐重挫微软
  3. stm32 硬件IIC使用方法说明与示例---LIS3DH的IIC通信
  4. y9000x2022开机黑屏时间长
  5. 正则里的(.*?)是什么意思
  6. 学习Python中turtle模块的基本用法(5:绘制简笔画羊)
  7. 无约束优化:Hessian-Free Optimization 拟牛顿类算法(BFGS,L-BFGS)
  8. 检测电脑有没有装旺旺-2
  9. gdb调试宏定义并显示宏定义的值
  10. RHCSA学习 --- 在VMware上创建虚拟机并安装红帽linux系统