C国演义 [第九章]

news2024/11/20 14:19:20

第九章

  • 买卖股票的最佳时机III
    • 题目理解
    • 步骤
      • dp数组
      • 递推公式
      • 初始化
      • 遍历方向
    • 代码
  • 买卖股票的最佳时机IV
    • 题目理解
    • 步骤
      • dp数组
      • 递推公式
      • 初始化
      • 遍历方向
    • 代码

买卖股票的最佳时机III

力扣链接

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易

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

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

示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票

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

示例 4:
输入:prices = [1]
输出:0

  • 提示:
    1 <= prices.length <= 105
    0 <= prices[i] <= 105

题目理解

这个题目和 买卖股票的最佳时机II 是很相似的, 但是有一点不同:
买卖股票的最佳时机II 是不限制买卖股票的次数, 而买卖股票的最佳时机III 是最多只能买卖股票两次

步骤

dp数组

每一天的状态:
dp[i][0] — — 第 i 天不做任何处理
dp[i][1] — — 第 i 天第一次持有股票 获取的最大利润
dp[i][2] — — 第 i 天第一次不持有股票 获取的最大利润
dp[i][3] — — 第 i 天第二次持有股票 获取的最大利润
dp[i][4] — — 第 i 天第二次不持有股票 获取的最大利润

递推公式

  • dp[i][1]:
    有两种选择:
    1.前天都是持有股票状态的 — — dp[i - 1][1]
    2.第 i 天才第一次购买股票的 — — dp[i - 1][0] - prices[i]
    ⇒ dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])

  • dp[i][2]:
    有两种选择:
    1.前天是不持有股票的状态 — — dp[i - 1][2]
    2.第 i 天才卖出股票 — — dp[i - 1][1] + prices[i]
    ⇒ dp[i][2] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])

  • dp[i][3]:
    有两种选择:
    1.前天是已经是第二次购买股票的状态 — — dp[i - 1][3]
    2.前天是第一次不持有股票的状态, 第 i 天才购买股票 — — dp[i - 1][2] - prices[i]
    ⇒ dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i])

  • dp[i][4]:
    有两种选择:
    1.前天已经是第二次不持有股票的状态 — — dp[i - 1][4]
    2.前天是第二次持有股票的状态, 第 i 天才卖出股票 — — dp[i - 1][3] + prices[i]
    ⇒ dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i])

初始化

dp[0][0] — — 第 1 天不做任何处理 — — dp[0][0] = 0(这个状态可以不看)
dp[0][1] — — 第 1 天第一次持有股票 获取的最大利润 — — dp[0][1] = -prices[0]
dp[0][2] — — 第 1 天第一次不持有股票 获取的最大利润 — — 可以看做当天买当天买 — — dp[0][2] = 0
dp[0][3] — — 第 1 天第二次持有股票 获取的最大利润 — — 可以看做是当天买当天买, 当天又买了一次 — — dp[0][3] = -prices[0]
dp[0][4] — — 第 1 天第二次不持有股票 获取的最大利润 — — 可以看做是当天买当天买, 当天又买了当天又卖了 — — dp[0][4] = 0

遍历方向

由递归公式, 我们可以发现第 i 天的状态是由第 i - 1 天的状态推导而来的
⇒ 遍历顺序是从前往后的

代码

class Solution {
public:
    int maxProfit(vector<int>& prices) 
    {
        int len = prices.size();
        vector<vector<int>> dp(len, vector<int>(5));
        
        dp[0][0] = 0; // 不做任何处理
        dp[0][1] = -prices[0]; // 第一次持有股票
        dp[0][2] = 0; // 第一次不持有股票
        dp[0][3] = -prices[0]; // 第二次持有股票
        dp[0][4] = 0; // 第二次不持有股票
        
        for(int i = 1; i < len; i++)
        {
            dp[i][0] = dp[i - 1][0];
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
            dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
            dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
            dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
        }
        
        return dp[len - 1][4];
    }
};

买卖股票的最佳时机IV

力扣链接
给定一个整数数组 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

  • 提示:
    0 <= k <= 100
    0 <= prices.length <= 1000
    0 <= prices[i] <= 1000

题目理解

这个题目和上面的 买卖股票的最佳时机III 是很相似的, 但是有一点是不同的:
买卖股票的最佳时机III 是购买股票的次数 <= 2, 而买卖股票的最佳时机IV 是购买股票的次数 <= k
⇒ 这个题目是对上个题目的 抽象总结

步骤

dp数组

dp[i][0] — — 第 i 天不做任何处理(这个状态可以不看)
dp[i][1] — — 第 i 天第一次持有股票 获取的最大利润
dp[i][2] — — 第 i 天第一次不持有股票 获取的最大利润
dp[i][3] — — 第 i 天第二次持有股票 获取的最大利润
dp[i][4] — — 第 i 天第二次不持有股票 获取的最大利润

我们发现: 每一次的买入和卖出都是有两个状态的⇒ 那么 k次买入和卖出, 是有2 * k个状态的

递推公式

  • dp[i][1]:
    有两种选择:
    1.前天都是持有股票状态的 — — dp[i - 1][1]
    2.第 i 天才第一次购买股票的 — — dp[i - 1][0] - prices[i]
    ⇒ dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])

  • dp[i][2]:
    有两种选择:
    1.前天是不持有股票的状态 — — dp[i - 1][2]
    2.第 i 天才卖出股票 — — dp[i - 1][1] + prices[i]
    ⇒ dp[i][2] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])

  • dp[i][3]:
    有两种选择:
    1.前天是已经是第二次购买股票的状态 — — dp[i - 1][3]
    2.前天是第一次不持有股票的状态, 第 i 天才购买股票 — — dp[i - 1][2] - prices[i]
    ⇒ dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i])

  • dp[i][4]:
    有两种选择:
    1.前天已经是第二次不持有股票的状态 — — dp[i - 1][4]
    2.前天是第二次持有股票的状态, 第 i 天才卖出股票 — — dp[i - 1][3] + prices[i]
    ⇒ dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i])

dp[i][0] = dp[i - 1][0]
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);

⇒ 通过上面的一系列, 我们发现: 周期是2, 且每一次的状态都是有规律的
我们可以用一个变量 i 来表示元素的个数(len), 用一个变量 j 来表示每次持有股票的状态(持有 或 非持有)

for(int i = 1; i < len; i++)
{
    for(int j = 1; j <= 2*k; j += 2)
    {
        dp[i][j] = max(dp[i - 1][j], dp[i - 1][j-1] - prices[i]);
        dp[i][j + 1] = max(dp[i-1][j+1], dp[i-1][j] + prices[i]);
    }
}

初始化

归根于第一次的情况, 即 dp[0][1 ... ... 2 * k]
不过, 通过前面的规律, 我们可以发现: 我们每次的 j 为奇数时, 是买入, 是 -prices[0]; 每次的 j 为偶数时, 是卖出, 是 0

for(int j = 1; j <= 2 * k; j += 2)
	dp[0][j] = -prices[0];

遍历方向

通过递推公式, 我们不难发现:
从前至后的遍历顺序

代码

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) 
    {
        int len = prices.size();
        vector<vector<int>> dp(len, vector<int>(2*k+1, 0));
        
        for(int j = 1; j <= 2*k; j += 2)
	        dp[0][j] = -prices[0];
        
        for(int i = 1; i < len; i++)
        {
            for(int j = 1; j <= 2*k; j += 2)
            {
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j-1] - prices[i]);
                dp[i][j + 1] = max(dp[i-1][j+1], dp[i-1][j] + prices[i]);
            }
        }
        
        return dp[len-1][2*k];
    }
};


你永远要宽恕众生,不论他有多坏,甚至他伤害过你,你一定要放下,才能得到真正的快乐 — — 路遥

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

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

相关文章

每日科技分享-POE新增文件和链接发送功能

POE推出新功能 注意POE需要魔法上午才能进去。 实测 实测可以发送论文给chatgpt&#xff0c;然后和AI进行共享的对话。 POE网站链接&#xff1a; 也可以发送链接&#xff0c;实测了一下&#xff0c;似乎有时候并不准确&#xff0c;我发送了关于分层强化的文章&#xff0c;但是…

按首字母排序分组(类通讯录)

移动端开发过程中&#xff0c;有遇到按首字母分组排序的&#xff0c;仿通讯录效果 那实现过程中&#xff0c;我们需要安装插件 npm i --save js-pinyin 安装后使用&#xff1a; 在页面中引用 import Pinyin from js-pinyin 调用 const sortByFirstLetter (origin) &g…

笔记本电脑的电池健康:确保长时间使用和优异性能的关键

笔记本电脑已经成为我们日常生活中不可或缺的工具&#xff0c;无论是办公、学习还是娱乐&#xff0c;我们都依赖着它的便携性和高效性能。而在所有的硬件组件中&#xff0c;电池健康被认为是确保长时间使用和良好性能的关键因素之一。一块健康的电池不仅能提供持久的续航时间&a…

从零开始的抢购脚本开发-油猴开发教程(多快好省)

文章目录 前言为何学习 JavaScript&#xff1f; JS简介JavaScript 能够改变 HTML 内容 JavaScript 能够改变 HTML 属性JavaScript 能够改变 HTML 样式 (CSS)JavaScript 能够隐藏 HTML 元素JavaScript 能够显示 HTML 元素JS的使用外部脚本外部 JavaScript 的优势外部引用JavaScr…

【JavaEE】了解JVM

JVM的基本认识 文章目录 【JavaEE】了解JVM1. JVM中的内存区域划分1.1 JVM的核心区域1.2 JVM内存城防图 2. JVM的类加载机制2.1 loading2.2 verification2.3 preparation2.4 resolution2.5 initialization2.6 类加载触发的时机2.7 双亲委派模型 3. JVM中的垃圾回收策略3.1 JVM释…

cmake 提前结束处理命令: return

有时候,我们有这样的需求,当处理到某个地方的时候,后面的我们都不想处理或者不需要处理的时候,就可以提前结束当前的处理逻辑,回到父级去处理.在C/C中,我们有break关键字跳出当前循环,continue关键字进入下一次循环,return关键字返回当前处理的函数. cmake也提供了break(),con…

浅谈电脑城的衰退是好是坏社会现象_kaic

在过去很长一段时间里&#xff0c;想要购买电子设备都逃不开一个叫“电脑城”的地方&#xff0c;那里鱼龙混杂良莠不齐&#xff0c;是令许多人记忆深刻分外难忘之处。 但是随着时代发展电商兴起&#xff0c;采用传统线下销售的电脑城却逐渐衰退甚至面临消失&#xff0c;对此你怎…

7-3 打怪升级

B0->途经堡垒1->...->B 总耗费能量 武器总价值输入样例: 6 12 1 2 10 5 2 3 16 20 3 1 4 2 2 4 20 22 4 5 2 2 5 3 12 6 4 6 8 5 6 5 10 5 6 1 20 25 1 5 8 5 2 5 2 1 2 6 8 5 4 2 3 6 5输出样例: 5 5->2 2 1 5->1->3 12 7 5->4->6 10 7 5 0 0#inclu…

目标检测——R-CNN网络基础

目录 Overfeat模型RCNN模型算法流程候选区域生成CNN网络提取特征目标分类&#xff08;SVM&#xff09;目标定位预测过程 算法总结 Fast RCNN模型算法流程ROI Pooling目标分类和回归 模型训练模型总结 Overfeat模型 RCNN模型 算法流程 候选区域生成 CNN网络提取特征 目标分类&am…

osg osgText::Text 中文乱码问题修复 解决中

osg osgText::Text 中文乱码问题修复 解决中 #include <osgDB/ConvertUTF>osg::Camera* osgWidget::createTextHUD() { osgText::Font* fontHei osgText::readFontFile("Fonts/simkai.ttf");text->setFont(fontHei);// 步骤二&#xff1a;设置 文字颜…

浅谈分布式系统 - 架构演进

目录 1. 架构演进 1.1 单机架构 1.2 什么是分布式架构 1.3 数据库和应用分离 1.4 引入负载均衡 1.5 引入数据库读写分离 1.6 引入缓存 1.7 数据库分库分表 1.8 微服务架构 2. 分布式系统下的常见概念 1. 架构演进 1.1 单机架构 单机架构只有一台服务器, 这个服务器…

HTML+CSS+JavaScript:渲染柱形统计图

一、需求 用户输入四个季度的数据&#xff0c;根据数据生成柱形统计图&#xff0c;浏览器预览效果如下 二、完整代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content&q…

Java利用POI导入Excel数据(多个sheet、模板)

需求&#xff1a;根据excel模板导入数据 sheet1&#xff1a;1-6行为固定格式&#xff0c;且需要取值({xxx});7行开始为数据集合(list) sheet2&#xff1a;都为固定格式&#xff0c;取值地方&#xff1a;{xxx} 1、数据格式&#xff08;两个Sheet&…

从零开始理解Linux中断架构(19)--中断线程化irq_thread

前面一节讲到的中断流处理流程是在hard_irq 流程上&#xff0c;工作在中断堆栈上。还有一种情况是使用中断线程的情形。request_threaded_irq参数中有两个处理函数handler,thread_fn是有区别的。handler主中断处理例程&#xff0c;运行hard_irq 流程上。而如果驱动程序填写thre…

利用R分别绘制配对连线散点图、云雨图、山脊图

大家好&#xff0c;我是带我去滑雪&#xff01; 精美的科研绘图总会给人眼前一亮&#xff0c;今天学习利用R绘制多组配对连线散点图、云雨图、山脊图&#xff0c;这三幅图最近都曾出现在Nature Communications (IF 16.6)中&#xff0c;比如配对连线散点图&#xff0c;如下所示&…

AI智能助手的未来:与人类互动的下一代人工智能技术

自我介绍⛵ &#x1f4e3;我是秋说&#xff0c;研究人工智能、大数据等前沿技术&#xff0c;传递Java、Python等语言知识。 &#x1f649;主页链接&#xff1a;秋说的博客 &#x1f4c6; 学习专栏推荐&#xff1a;人工智能&#xff1a;创新无限、MySQL进阶之路、C刷题集、网络安…

AIGC文生图:使用ControlNet 控制 Stable Diffusion

1 ControlNet介绍 1.1 ControlNet是什么&#xff1f; ControlNet是斯坦福大学研究人员开发的Stable Diffusion的扩展&#xff0c;使创作者能够轻松地控制AI图像和视频中的对象。它将根据边缘检测、草图处理或人体姿势等各种条件来控制图像生成。 论坛地址&#xff1a;Adding…

操作系统进行设备控制的方式

一.I/O控制方式 上一篇的博客介绍了设备管理的一些概念基础知识点&#xff0c;其中I/O控制方式这一块没有详细说明。设备管理的主要任务之一是控制设备和内存或CPU之间的数据传送。外围设备和内存之间的输入/输出控制方式有4种&#xff0c;下面分别加以介绍。 二.程序直接控制…

ITIL 4—事件管理实践

1 关于本文 本文档提供事件管理实践实用指南。分为五个主要部分&#xff0c;内容包括&#xff1a; 本实践的一般信息实践的流程和活动及其在服务价值链中的作用参与实践的组织和人员支持实践的信息和技术对实践的合作伙伴和供应商的考虑。 1.1 ITIL4 认证方案 本文档的部分…

Ubuntu 安装 Docker

本文目录 1. 卸载旧版本 Docker2. 更新及安装工具软件2.1 更新软件包列表2.2 安装几个工具软件2.3 增加一个 docker 的官方 GPG key2.4 下载仓库文件 3. 安装 Docker3.1 再次更新系统3.2 安装 docker-ce 软件 4. 查看是否启动 Docker5. 验证是否安装成功 1. 卸载旧版本 Docker …