< 每日算法 - JavaScript解析:一文解决 “ 买卖股票 ” 系列算法题 >

news2024/11/15 2:05:23

在这里插入图片描述

每日算法 - JavaScript解析:一文解决 “ 买卖股票 ” 系列算法题

  • 一、基础题目
    • > 题目
    • > 解题思路
      • 定义操作
      • 定义状态
      • 动态规划值所需变量
      • 完整代码
  • 二、添加条件:`当交易次数为 ∞ 时`
    • > 题目
    • > 解决思路
  • 三、添加条件:`当交易次数为 K = number 时`
    • > 题目
    • > 解决思路
  • 四、添加条件: 每次交易时,扣除 fee 数额的手续费
  • 👉 结论
  • 往期内容 💨


本篇文章涉及题目均来自 leetCode

  • 121.买卖股票的最佳时机(简单): 限定交易次数 k=1
  • 122. 买卖股票的最佳时机 II(中等) : 交易次数无限制 k = +infinity
  • 123.买卖股票的最佳时机 III (困难) : 限定交易次数 k=2
  • 188.买卖股票的最佳时机 IV (困难) : 限定交易次数 最多次数为 k
  • 309.最佳买卖股票时机含冷冻期(中等) : 含有交易冷冻期
  • 714.买卖股票的最佳时机含手续费 (中等) : 每次交易含手续费

小温建议各位小伙伴看完,立马去leetCode上手写写,毕竟俗话说的好: 好记性不如烂笔头

一、基础题目

接下来,就由小温带大家解决 “买卖股票”系列算法题, 以最基础的 121 题:买卖股票的最佳时机(简单) 为例,讲解解决思路:

> 题目

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票( 此段话表示,只允许交易一次,也就是买和卖各一次。k = 1 )。

设计一个算法来计算你所能获取的最大利润,返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0

> 解题思路

阐述效果图

通过上图可以知道,我们需要借助已知的数据,配合定义未知的变量去推出最大利润! 而定义这个推理公式的方法,叫做 “ 动态规划 ”。需要清楚各个数据之间的练习,接下来分析一下需要定义那些已知常量未知的变量

根据题目可以知道每天的股票的波动数据,结合常识,需要定义以下内容:

定义操作

  • 买入
  • 卖出
  • 不操作

定义状态

  • i: 天数
  • k: 交易次数,每次交易包含买入和卖出,这里我们只在买入的时候需要将 k - 1
  • 0: 不持有股票时,买入费用
  • 1: 持有股票时开销,包含购入的价格,所以计算利润时,需要减去购入价格

动态规划值所需变量

  • dp[i][k][0] : 第 i 天 第 k 次交易中,手中无股票, 计算公式为:当天股票价格 - 购入股票的费用。
  • dp[i][k][1] : 第 i 天 第 k 次交易中,手中有股票,买入股票的费用。

效果图

// 今天没有持有股票,分为两种情况
// 1. dp[i - 1][k][0],昨天没有持有,今天不操作。 
// 2. dp[i - 1][k][1] + prices[i] 昨天持有,今天卖出,今天手中就没有股票了。
dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])


// 今天持有股票,分为两种情况:
// 1.dp[i - 1][k][1] 昨天持有,今天不操作
// 2.dp[i - 1][k - 1][0] - prices[i] 昨天没有持有,今天买入。
dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])

//最大利润就是这俩种情况的最大值

====> 由于 此题k为1,所以转化为以下情况 <====

//第i天不持有 由 第i-1天不持有然后不操作 和 第i-1天持有然后卖出 两种情况的最大值转移过来
dp[i][1][0] = Math.max(dp[i - 1][1][0], dp[i - 1][1][1] + prices[i])

//第i天持有 由 第i-1天持有然后不操作 和 第i-1天不持有然后买入 两种情况的最大值转移过来
dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i])
            = Math.max(dp[i - 1][1][1], -prices[i])
            // k=0时 没有交易次数,dp[i - 1][0][0] = 0

k是固定值1,不影响结果,所以可以不用管,简化之后如下:

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

完整代码

//时间复杂度O(n) 空间复杂度O(n),dp数组第二维是常数
const maxProfit = function (prices) {
    let n = prices.length;
    let dp = Array.from(new Array(n), () => new Array(2));
    dp[0][0] = 0; //第0天不持有
    dp[0][1] = -prices[0]; //第0天持有
    for (let i = 1; i < n; 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], -prices[i]);
    }
    return dp[n - 1][0];
};

状态压缩,dp[i] 只和 dp[i - 1] 有关,去掉一维

//时间复杂度O(n) 空间复杂度O(1)
const maxProfit = function (prices) {
	let n = prices.length;
	let dp = Array.from(new Array(n), () => new Array(2));
	dp[0] = 0;
	dp[1] = -prices[0];
	for (let i = 1; i < n; i++) {
	    dp[0] = Math.max(dp[0], dp[1] + prices[i]);
	    dp[1] = Math.max(dp[1], -prices[i]);
	}
	return dp[0];
};

//语意化
const maxProfit = function (prices) {
    let n = prices.length;
    let sell = 0;
    let buy = -prices[0];
    for (let i = 1; i < n; i++) {
        sell = Math.max(sell, buy + prices[i]);
        buy = Math.max(buy, -prices[i]);
    }
    return sell;
};

二、添加条件:当交易次数为 ∞ 时

  • 122. 买卖股票的最佳时机 II(中等) : 交易次数无限制 k = +infinity

> 题目

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     总利润为 4 + 3 = 7

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     总利润为 4

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0

> 解决思路

股票对应的题目,只要能理解第一题的动态规划公式,能理解推论,基本上大致都相同。在添加交易次数为无穷的时候,只需要在下一次买入时,加上上次交易剩余的利润即可,在 k 同样不影响结果,简化之后如下:

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])

语意化之后的核心代码如下:

sell = Math.max(sell, buy + prices[i])
buy = Math.max(buy, sell - prices[i])

三、添加条件:当交易次数为 K = number 时

  • 123.买卖股票的最佳时机 III (困难) : 限定交易次数 k=2

> 题目

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格,和一个整型 k 。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入:k = 2, prices = [2,4,1]
输出:2
解释:在第 1  (股票价格 = 2) 的时候买入,在第 2  (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2

示例 2:

输入:k = 2, prices = [3,2,6,5,0,3]
输出:7
解释:在第 2  (股票价格 = 2) 的时候买入,在第 3  (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
     随后,在第 5  (股票价格 = 0) 的时候买入,在第 6  (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3

> 解决思路

根据题目可以得出,我们不能只基于股票数据数组来循环,需要将每个数据假设它交易 K 次,取所有可能的最大利润值!

所以在我们运算时,需要借助 二维数组 或者是 对象数组 来进行缓存,缓存上次最优解的购入和售出的利润! 在当次计算时,加上上次交易带来的利润进行运算。

具体逻辑如下:

/**
 * @param {number} k
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(k, prices) {
    let len = prices.length
	// 定义缓存变量,缓存每次交易的购入和售出费用
    let pricesList = new Array(k)
    for(let j = 0; j <= k; j++) {
        pricesList[j] = {
            buy: -prices[0],
            sell: 0
        }
    }



    for(let i = 0; i < len; i++) {
        for(let j = 1; j <= k; j++) {
            pricesList[j].buy = Math.max(pricesList[j].buy, pricesList[j - 1].sell - prices[i])
            pricesList[j].sell = Math.max(pricesList[j].sell, pricesList[j].buy + prices[i])
        }
    }
    return pricesList[k].sell
};

本质还是和上一题,交易次数为无穷的时差不多的核心代码,属于是换汤不换药了! 只需要在本次计算时,加上上次剩余的利润即可!

四、添加条件: 每次交易时,扣除 fee 数额的手续费

  • 714.买卖股票的最佳时机含手续费 (中等) : 每次交易含手续费

这题是122题的变种,我们需要知道,当每次交易卖出时,为该次交易结束。在交易结束时,对总利润减去本次交易的手续费即可!

核心代码如下:

buy = Math.max(buy, sell - prices[i])
sell = Math.max(sell, buy + prices[i] - fee)

👉 结论

通过本篇文章的讲述,相信大家基本上能搞懂 “ 买卖股票 ” 系列的动态规划公式了,万变不离其宗! 只要能理解:买入和卖出 及 当天股票价格之间的关系,基本上都能推出了!好了,感谢各位小伙伴读到这里,如果感觉对你有所帮助,请勿吝惜你的小手指呀!给小温一个三连吧!

往期内容 💨

🔥 < 每日算法:一文带你认识 “ 双指针算法 ” >

🔥 < 每日小技巧: 基于Vue状态的过渡动画 - Transition 和 TransitionGroup>

🔥 < JavaScript技术分享: 大文件切片上传 及 断点续传思路 >

🔥 < 每日份知识快餐:axios是什么?如何在Vue中 封装 axios ? >

🔥 < 面试知识点:什么是 Node.js ?有哪些优缺点?应用场景? >

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/729295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小机器人在现实世界中学会快速驾驶

小机器人在现实世界中学会快速驾驶 —强化学习加上预训练让机器人赛车手加速前进— Without a lifetime of experience to build on like humans have (and totally take for granted), robots that want to learn a new skill often have to start from scratch. Reinforceme…

【案例教程】GIS在地质灾害危险性评估与灾后重建中的实践技术应用及python机器学习灾害易发性评价模型建立与优化

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

AI对话宝-智能AI在线问答写作

AI对话宝的工作原理是基于自然语言处理技术。当用户与其进行交互时&#xff0c;AI对话宝会根据用户的输入&#xff0c;通过算法和模型来理解用户的意图&#xff0c;并给出相应的回答&#xff0c;并且系统还可以不断学习并优化其回答&#xff0c;从而提高其交互的效率和准确性。…

批量提取目录下的所有文件名称放至Excel表格中,方便快捷,快来试试吧

批量提取目录下的所有文件名称放至Excel表格中&#xff0c;方便快捷&#xff0c;快来试试吧 Sina Visitor Systemhttps://weibo.com/tv/show/1034:4920955869265935?fromold_pc_videoshow

binwalk-解包工具

一、binwalk介绍 二、安装binwalk # 1. 安装依赖和binwalk ​git clone https://github.com/ReFirmLabs/binwalk.git cd binwalk sudo python ./setup.py uninstall # 如果您有以前安装的 Binwalk 版本&#xff0c;建议您在升级之前将其卸载 sudo ./deps.sh # 安装依赖项 sud…

C语言学习(三十五)---动态内存练习题与柔性数组

经过前面的内容&#xff0c;我们已经对动态内存的知识已经有了相当多了了解&#xff0c;今天我们再做几道有关动态内存的练习题&#xff0c;然后再介绍一下柔性数组&#xff0c;好了&#xff0c;话不多说&#xff0c;开整&#xff01;&#xff01;&#xff01; 动态内存练习题…

上海亚商投顾:沪指失守3200点 两市成交不足8000亿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 沪指今日延续调整&#xff0c;失守3200点关口&#xff0c;深成指、创业板指盘中均跌超1%。AI概念股集体下挫&#…

你会做接口测试吗?接口测试面试题盲扫(附答案)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 为什么要做接口测…

【跑实验06】如何数据集中加入图像尺寸?如何把tuple格式的坐标按顺序写成四列数据?如何把某一列放到最后?

文章目录 一、如何数据集中加入图像尺寸&#xff1f;二、如何把tuple格式的坐标按顺序写成四列数据&#xff1f;三、如何把某一列放到最后&#xff1f; 一、如何数据集中加入图像尺寸&#xff1f; 部分核心代码如下&#xff1a; image_files [filename for filename in os.l…

Windows | \\wsl.localhost无法访问

Windows | \\wsl.localhost无法访问 在地址栏输入&#xff1a;\\wsl.localhost或者\\wsl.localhost\

解决新版Pyahcrm2023.1.2版本没有manage repositories按钮无法更改依赖源的问题及使用Pycharm安装库的新理解

本文章的理解基于下面两篇文章&#xff1a; https://blog.csdn.net/henu1710252658/article/details/130918206 https://blog.csdn.net/henu1710252658/article/details/82015796 问题一&#xff1a;新版Pyahcrm2023.1.2版本没有manage repositories按钮无法更改依赖源 首先&am…

高效读深度学习代码:如何又快又好的get代码的逻辑与思想

犹豫很久要不要把读代码这个事情专门挑出来写成一篇推文。毕竟读代码嘛&#xff0c;大家可能都会读。而且笔者个人读的和写的代码量也并不足以到指导大家读代码的程度。但笔者还是决定大胆地写一点&#xff1a;就当是给自己设立今后读代码的标准&#xff0c;也将一些之前未能践…

浏览器相关面试题

1、在浏览器中输入URL并回车后发生了什么 https:www.baidu.com url > 统一资源定位发&#xff0c;&#xff08;网址&#xff09; 是IP的一个映射&#xff0c;方便记忆 https&#xff1a;传输协议&#xff08;http和TCP之间加了一层TSL或者SSL的安全层&#xff09; www&a…

在Ubuntu中禁用和启用CPU内核详解

概要 在某些情况下&#xff0c;您可能需要在Ubuntu操作系统中禁用或启用CPU内核。禁用CPU内核可以帮助您降低功耗&#xff0c;提高性能或解决一些与硬件和软件兼容性相关的问题。本文将介绍如何在Ubuntu中禁用和启用CPU内核的方法。 方法一&#xff1a;使用GRUB配置 GRUB是Ubu…

谷歌验证码kaptcha使用(包括前端获取获取解析)

1.后端 基于springboot开发。 包结构 1.导入依赖 <!--kaptcha验证码生成器--><dependency><groupId>com.github.axet</groupId><artifactId>kaptcha</artifactId><version>0.0.9</version></dependency> 2.配置类 …

从零开始:深度学习入门资料推荐

还记得几年前刚入坑的时候&#xff0c;老师给的入门资料就是一堆论文&#xff01;害的我差点放弃。。。 如今深度学习应用的开发成本越来越低&#xff0c;学习资料越来越多&#xff0c;于是对初学者来说进入了另一个相反的困境——资料过多&#xff0c;让人眼花缭乱&#xff0…

ASEMI整流桥MB6S是什么电子元件

编辑-Z 在电子工程领域&#xff0c;整流器是一种常见的电子设备&#xff0c;用于将交流电&#xff08;AC&#xff09;转换为直流电&#xff08;DC&#xff09;。其中&#xff0c;整流桥MB6S是一种广泛使用的整流器&#xff0c;以其高效、稳定和可靠的性能赢得了工程师们的青睐…

[Container]Hadoop集群镜像打包

文章目录 Docker DNS配置Linux Docker DNS设置Windows、MacOs Docker DNS设置 打包HadoopDockerfile打包文件参数声明和基础镜像引入安装相关依赖库创建普通用户下载或导入软件包环境变量配置 初始化脚本参数配置${HADOOP_CONF_DIR}/workers工作节点${HADOOP_CONF_DIR}/hadoop-…

97、基于stm32单片机智能药箱药盒温湿度体温光照时钟wifi手机APP监控(程序+原理图+PCB源文件+手机APP源码+硬件设计资料+元器件清单等)

单片机类型选择 方案一&#xff1a;可以使用现在比较主流的单片机STC89C5单片机进行数据处理。这款单片机具有的特点是内存和51的单片机相比多了4KB内存&#xff0c;但是价格和51单片机一样。并且支持数据串行下载和调试助手。此款单片机是有ATMEL公司生产&#xff0c;可用5V电…

appium自动化测试之PO模型设计

目录 PO模型 PO分层 PO模型设计框架 config目录 common目录 pages目录 function目录 case目录 logs目录 report目录 runTest.py文件 总结&#xff1a; 我们在做自动化的时候应该都听过PO模型&#xff0c;那么什么是PO模型呢&#xff1f;PO模型在自动化中的作用是什…