C国演义 [第九章]

第九章

  • 买卖股票的最佳时机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];
    }
};


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

制作Visual Studio离线安装包

vs2015之后官网就不提供离线安装包了&#xff0c;使用离线安装包就需要自己手动制作一个&#xff1b; 以vs2019为例&#xff1a; 先去官网下载在线安装器 官网下载地址&#xff1a;Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com) 展开2019的标签…

2023.7.15

同余最短路 P3403 跳楼机 题意&#xff1a;给定h高的楼层&#xff0c;起始位置在第一层&#xff0c;可以选择操作向上移动x层或y层或z层&#xff0c;回到第一层 求可以到达的楼层数 思路&#xff1a;转化题意为求axbyczk(k在[1,h]&#xff0c;x,y,z为正整数,有多少k满足条件&am…

推荐一款IDEA神级插件【Bito】而且免费!

什么是Bito&#xff1f; Bito是一款在IntelliJ IDEA编辑器中的插件&#xff0c;Bito插件是由ChatGPT团队开发的&#xff0c;它是ChatGPT团队为了提高开发效率而开发的一款工具。ChatGPT团队是一支专注于自然语言处理技术的团队&#xff0c;他们开发了一款基于GPT的自然语言处理…

动态规划之118杨辉三角(第6道)

题目&#xff1a;给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 题目链接&#xff1a;118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 示例&#xff1a; 解法&#xff1…

C/C++实现高并发http服务器

http高并发服务器实现 基础知识 html&#xff0c;全称为html markup language&#xff0c;超文本标记语言。 http&#xff0c;全称hyper text transfer protocol&#xff0c;超文本传输协议。用于从万维网&#xff08;WWW&#xff1a;World Wide Web&#xff09;服务器传输超…

异地使用PLSQL远程连接访问Oracle数据库【内网穿透】

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 转载自cpolar极点云文章&#xff1a;公网远程连接…

Jenkins的几种安装方式以及邮件配置

目录 Jenkins介绍 Jenkins下载、安装 一、通过war包安装 二、通过docker安装 jenkins 容器中添加 git, maven 等组件 jenkins 容器中的公钥私钥 在 jenkins 容器中调用 docker 简单的方式启动 Docker server REST API 一个 jenkins 示例 三、通过Homebrew安装 访问Je…

【DC-DC】AP5193 DC-DC宽电压LED降压恒流驱动器 LED电源驱动IC

产品 AP5193是一款PWM工作模式,高效率、外围简单、内置功率MOS管&#xff0c;适用于4.5-100V输入的高精度降压LED恒流驱动芯片。最大电流2.5A。AP5193可实现线性调光和PWM调光&#xff0c;线性调光脚有效电压范围0.55-2.6V.AP5193 工作频率可以通过RT 外部电阻编程来设定&…

从源码全面解析 dubbo 消费端服务调用的来龙去脉

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码…

插入排序法解析

插入排序法解析 什么是插入排序法 插入排序法是一种简单但有效的排序算法&#xff0c;其基本思想是将一个待排序的元素逐个插入到已经排好序的元素序列中&#xff0c;直至所有元素都被插入完成&#xff0c;从而得到一个有序序列。 具体步骤如下&#xff1a; 假设初始时&…

redis实现相关分布式锁

为什么需要分布式锁 我们知道&#xff0c;当多个线程并发操作某个对象时&#xff0c;可以通过synchronized来保证同一时刻只能有一个线程获取到对象锁进而处理synchronized关键字修饰的代码块或方法。既然已经有了synchronized锁&#xff0c;为什么这里又要引入分布式锁呢&…

react useState useEffect useMemo实际业务场景中的使用

下面的代码实现了上面图片的功能 import React, { useMemo } from "react"; import "./HomeHead.less"; import Img from "../assets/images/timg.jpg";const HomeHead function HomeHead(props) {{ /*父组件传过来的值 */}let { today } pro…

在线培训系统的保障措施带来安全、可靠的学习环境

在今天的数字时代&#xff0c;越来越多的人选择在线培训系统作为学习的方式。然而&#xff0c;随着在线教育市场的不断增长&#xff0c;安全和可靠性成为消费者普遍关心的问题。因此&#xff0c;在线培训系统需要采取一系列保护措施以确保学生的数据和隐私得到保护&#xff0c;…

Flutter 状态管理框架 Provider 和 Get 分析

状态管理一直是 Flutter 开发中一个火热的话题。谈到状态管理框架&#xff0c;社区也有诸如有以Get、Provider为代表的多种方案&#xff0c;它们有各自的优缺点。面对这么多的选择&#xff0c;你可能会想&#xff1a;「我需要使用状态管理么&#xff1f;哪种框架更适合我&#…

集群基础1——集群概念、LVS负载均衡

文章目录 一、基本了解二、LVS负载均衡2.1 基本了解2.2 工作模式2.2.1 NAT模式2.2.2 DR模式2.2.3 LVS-TUN模式2.2.4 LVS-FULLNAT模式 三、调度器算法四、ipvsadm命令 一、基本了解 什么是集群&#xff1f; 多台服务器做同一件事情。 集群扩展方式&#xff1a; scale up&#xf…

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

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

05 Docker 安装常用软件 (mongoDB)

目录 1. mongoDB简介 1.1 mongodb的优势 2. mongodb的安装 2.1 创建数据文件夹 2.2 备份日志 2.3 配置文件夹 2.4 创建两个文件 ---> 2.4.1 配置如下: 2.5 拉取mongodb 2.6 运行容器 2.7 进入mongodb容器 ---> 2.7.0 高版本(6.0)以上是这样的 , 旧版的没研究 …

SpringBoot 集成 Mybatis

SpringBoot 集成 Mybatis 详细教程 &#xff08;只有操作&#xff0c;没有理论&#xff0c;仅供参考学习&#xff09; 一、操作部分 1. 准备数据库 1.1 数据库版本&#xff1a; C:\WINDOWS\system32>mysql -V mysql Ver 8.0.25 for Win64 on x86_64 (MySQL Community …

PyTorch深度学习实战(5)——计算机视觉

PyTorch深度学习实战&#xff08;5&#xff09;——计算机视觉 0. 前言1. 图像表示2. 将图像转换为结构化数组2.1 灰度图像表示2.2 彩色图像表示 3 利用神经网络进行图像分析的优势小结系列链接 0. 前言 计算机视觉是指通过计算机系统对图像和视频进行处理和分析&#xff0c;利…

笔记本电脑清灰换硅脂

文章目录 一、完整过程0.准备工具1.拆笔记本后盖2.洗手擦干断电3.清理部件浮尘4.拆风扇5.拆散热模具6.换硅脂7.装回去 二、图片 一、完整过程 0.准备工具 拆机螺丝刀、硅脂、撬片/撬棒、毛刷、气吹、卫生纸。 正常电脑是十字螺丝&#xff0c;推荐刀头使用 PH00 或 PH0。 1.拆…