【动态规划精选题目】3、简单多状态模型

news2025/1/19 14:35:03

此动态规划系列主要讲解大约10个系列【后续持续更新】

本篇讲解简单多状态模型中的9道经典题,会在讲解题目同时给出AC代码

目录

1、按摩师

2、力扣198:打家劫舍1

3、打家劫舍II

4、删除并获得点数

5、 粉刷房子

6、力扣309:买卖股票的最佳时机含冷冻期

7、 买卖股票的最佳时机含手续费

 8、买卖股票的最佳时机III

9、买卖股票的最佳时机IV


1、按摩师

示例分析: 

class Solution {
public:
    int massage(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) return 0;

        //创建两个dp表f和g
        vector<int> f(n);//n个数据都会初始化为0
        auto g = f;//创建g表
        f[0] = nums[0]; //初始化
        for (int i = 1; i < n; i++)
        {
            f[i] = g[i - 1] + nums[i];
            g[i] = max(f[i - 1], g[i - 1]);
        }
        return max(f[n - 1], g[n - 1]); 
    }
};

借多状态dp的题说明一下,怎么判断是一维dp还是二维dp呢?

由状态表示决定的,如果一维数组能表示清楚,就用一维的,表示不清楚,就可以尝试增加维数,用二维的,有时候其实三维的也有,但是情况少。 


2、力扣198:打家劫舍1

 这道题跟上道题的按摩师的思路和代码基本一样

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n);
         auto g = f;
         f[0] = nums[0];
         for (int i = 1; i < n; i++)
         {
             f[i] = g[i - 1] + nums[i];
             g[i] = max(g[i - 1], f[i - 1]);
         }
         return max(f[n - 1], g[n - 1]);
    }
};

3、打家劫舍II

这道题只是在上一道题的打家劫舍1中加了一个限制条件,即首尾也算相连,不能都偷窃,所以只需分类讨论下这个情况,再转换为打家劫舍1即可(下面的rob1表示的是可以偷的范围,也就是可以用打家劫舍1来求解的地方)

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        return max(nums[0] + rob1(nums, 2, n - 2), rob1(nums, 1, n - 1));
    }

    int rob1(vector<int>& nums, int left, int right)
    {
        if (left > right) return 0;//处理边界条件

        int n = nums.size();//按理说开right-left+1个空间即可,但这里多开几个也没事
        vector<int> f(n);
        auto g = f;
        f[left] = nums[left];//初始化
        for (int i = left + 1; i <= right; i++)
        {
            f[i] = g[i - 1] + nums[i];
            g[i] = max(f[i - 1], g[i - 1]);
        }
        return max(f[right], g[right]);
    }
};

4、删除并获得点数

 动态规划的预处理思路:

其实上面的思想就是利用哈希表中的直接映射法,那么这种方法就要找nums数组中的最大值,但是题目中已经给出了nums数组中每个值的范围,故可以直接开空间大小为最大值。并且这种方法既做到了数据有序又做到了连续 

整体思路: 

class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        const int N = 10001;//数组中的最大值为1万,多开1个防止越界问题
        //1、预处理
        int arr[N] = {0};
        for (const auto& x : nums) arr[x] += x;

        //2、利用打家劫舍思路求解该问题
        vector<int> f(N);
        auto g = f;
        //这里不用初始化了,因为f[0]=arr[0],可arr[0]本来就=0
        for (int i = 1; i < N; i++)
        {
            f[i] = g[i - 1] + arr[i];
            g[i] = max(f[i - 1], g[i - 1]);
        }
        
        return max(f[N - 1], g[N - 1]);
    }
};

5、 粉刷房子

解释示例1和示例2:

也就是判断当前位置是第几个房子,只需看行即可,列是代表颜色的 

 总体思路:

下面说的位置可以理解为是一个房子

理解本题的虚拟节点: 

class Solution {
public:
    int minCost(vector<vector<int>>& costs) {
        int n = costs.size();//得到的是行数,即现有的房子数
        vector<vector<int>> dp(n + 1, vector<int> (3));//多开一行给虚拟节点
        
        //从上到下遍历每个房子,算出每个房子对应不同颜色的价格
        for (int i = 1; i <= n; i++)
        {
            //因为多开了一个虚拟节点,所以要加上cost[i-1][0],这里要用i-1才行
            dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i- 1][0];
            dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i- 1][1];
            dp[i][2] = min(dp[i - 1][1], dp[i - 1][0]) + costs[i- 1][2];
        }

        return min(min(dp[n][0], dp[n][1]), dp[n][2]);
    }
};

6、力扣309:买卖股票的最佳时机含冷冻期

题目分析: 

如果是多状态,并且多状态之间可以相互转移的话 ,为了不忽略某种状态,我们可以画一个图,如下图,我们也称为这种图为状态机

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(3));//三个dp表
        dp[0][0] = -prices[0];//初始化 
        for (int i = 1; i < n; ++i)
        {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]);
            dp[i][2] = dp[i - 1][0] + prices[i];
        }
        //最佳答案一定不会是dp[n - 1][0],所以最后不用考虑在内
        return max(dp[n - 1][1], dp[n - 1][2]);
    }
};

7、 买卖股票的最佳时机含手续费

 示例解释:

 箭头起始位置:前一天结束后的状态,箭头指向位置:当天结束状态

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int n = prices.size();
        vector<int> f(n);
        auto g = f;
        f[0] = -prices[0];//初始化:第0天结束后处于买入状态
        for (int i = 1; i < n; i++)
        {
            f[i] = max(f[i- 1], g[i - 1] - prices[i]);
            g[i] = max(f[i - 1] + prices[i] - fee, g[i - 1]);
        }
        //最后一天手里还有股票,肯定就不是最优解,故不用考虑
        return g[n - 1];
    }
};

 当然,像之间那种开二维数组也可以,但是三种状态及以上才推荐开二维数组,下面这么写也可以


 8、买卖股票的最佳时机III

示例分析:

此题复杂在还要考虑交易的次数。

买入是指手里有股票的状态,卖出是指手里没股票,是一个可交易的状态。下图的线的含义,线的起点表示前一天结束后的状态,线表示当天的操作,箭头所指的表示当天结束后的状态 

 但是因为f和g表初始化的不一致,可又不想在循环外再初始化哪个特例,就用稍微修改状态转移方程的方法来便于统一的初始化

class Solution {
public:
    const int INF = 0x3f3f3f;//int最大值的一半
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> f(n, vector<int>(3, -INF));
        auto g = f;
        //初始化f和g表的第一行的第一个元素
        f[0][0] = -prices[0], g[0][0] = 0;
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);
                //天数不会越界,因为在这之前f和g表已经初始化了
                g[i][j] = g[i - 1][j];
                if (j - 1 >= 0)
                {   //要么j-1交易次数存在,则考虑这种情况,
                    //要么不存在,那么g[i][j]就直接=g[i-1][j]
                    g[i][j] = max(g[i][j], f[i -1][j - 1] + prices[i]);
                }
            }
        }
        //找到g表最后一行的最大值
        int ret = 0;
        for (int i = 0; i < 3; i++)
            ret = max(g[n - 1][i], ret);

        return ret;         
    }
};

9、买卖股票的最佳时机IV

本题跟买卖股票的最佳时机III的分析思路基本一模一样,但是本题多了一个细节问题,即优化时间复杂度

 

 

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        k = min(k, n / 2);//处理细节问题

        vector<vector<int>> f(n, vector<int>(k + 1, -INF));
        auto g = f;
        f[0][0] = -prices[0], g[0][0] = 0;
        for (int i = 1; i < n; i++)
        {//因为第一行已经初始化了,所以i从1开始
            for (int j = 0; j <= k; j++)
            {
                f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);
                g[i][j] = g[i - 1][j];
                if (j - 1 >= 0)
                    g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]);
            }
        }
        int ret = 0;
        for (int i = 0; i <= k; i++)
            ret = max(ret, g[n - 1][i]);

        return ret;
    }
};

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

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

相关文章

MySQL入门教程-触发器

9.触发器 什么是触发器 触发器(trigger)&#xff1a;监视某种情况&#xff0c;并进行某种操作&#xff0c;它的执行并不是程序调用&#xff0c;也不是手工启动&#xff0c;而是由事件来触发&#xff0c;例如&#xff1a;对一张表进行操作&#xff08;插入&#xff0c;更新&…

Winform RDLC报表(数据库连接、报表函数使用、动态表头)

文章目录 NuGet安装库数据库连接报表设计报表引用添加报表 数据集设计方法一手动添加方法二——连接数据库添加 关联报表与数据集表格数据与数据集数据设计表格格式、字体设计报表数据字段绑定 Winform 使用报表控件数据库填充数据集从数据库获取与数据源相同字段的数据 动态表…

城市生态数据大屏,PSD设计稿

现分享生态系统可视化大数据大屏的 Photoshop 源文件&#xff0c;下载即用&#xff01;以下为截图示意。 若需 更多行业 相关的大屏&#xff0c;请移步小7的另一篇文章&#xff1a;200套精选数据可视化大屏&#xff0c;大屏PSD设计&#xff08;各行业大屏UI&#xff09;https:…

Pandas教程(一)—— 数据结构

前言 Pandas是贯穿数据分析的主要工具之一&#xff0c;它经常和其他数值计算工具一起使用&#xff08;例如&#xff1a;Numpy、SciPy和matplotlib&#xff09;。尽管pandas采用了很多NumPy的代码风格&#xff0c;但二者最大的区别是&#xff1a;pandas主要用于处理表格型或异质…

机器学习系列11:减少过拟合——L1、L2正则化

如果我们注意到模型在训练集上的表现明显优于模型在测试集上的表现&#xff0c;那么这就是模型过拟合了&#xff0c;也称为 high variance。 产生的过拟合的原因是对于给定的训练集数据来说&#xff0c;模型太复杂了。有几种可以减少过拟合的方法&#xff1a; 收集更多的训练数…

洛谷 P1086:花生采摘 ← 结构体

【题目来源】https://www.luogu.com.cn/problem/P1086https://www.acwing.com/problem/content/description/420/【题目描述】 在告示牌背后&#xff0c;路边真的有一块花生田&#xff0c;花生植株整齐地排列成矩形网格&#xff08;如图 1&#xff09;。 有经验的多多一眼就能看…

Net6 Core webApi发布到IIS

Net6 Core Api发布到IIS不同于webapi&#xff0c;依赖框架不同&#xff0c;配置也移至项目内Program.cs 一、发布到指定文件夹和IIS&#xff0c;不过注意IIS应用程序池选择的是 “无托管代码“ 在IIS管理器中点击浏览&#xff0c;访问接口路径报500.19&#xff0c;原因是所依赖…

Prometheus告警处理

Alertmanager介绍 Prometheus 包含一个报警模块&#xff0c;就是 AlertManager&#xff0c;Alertmanager 主要用于接收 Prometheus 发送的告警信息&#xff0c;它支持丰富的告警通知渠道&#xff0c;而且很容易做到告警信息进行去重、降噪、分组等&#xff0c;是一款前卫的告警…

链表精选题集

目录 1 链表翻转 题目链接&#xff1a; 解题&#xff1a; 试错版&#xff1a; 2 找中间节点 题目链接: 题解&#xff1a; 3 找倒数第k个节点 题目链接&#xff1a; 题解&#xff1a; 4 将两个升序链表合并为一个升序链表 题目链接&#xff1a; 题解&#xff1a; …

[电磁学]猴博士不挂科

1 利用表格求场强 2 利用叠加求场强 3 利用积分求场强 电场立库仑力 球的面积公式是4πr&#xff0c;其中r为球的半径。 球的体积公式是(4/3)πr&#xff0c;其中r为球的半径。 带电物体有体积:

软件测试/测试开发丨Python 内置库 OS 学习笔记分享

os 概述 os: Operating System os 使用 导入 os 模块 查看 os 模块使用文档 help(os)dir(os) import os# 查看os模块说明文档 help(os)# 查看os模块的属性和方法 print(dir(os))os 操作系统相关 os.name&#xff1a;获取系统名称os.environ&#xff1a;获取系统环境变量信…

是时候将javax替换为Jakarta了

开始 相信很多朋友在使用新版本的Spring的时候&#xff0c;发现了一些叫jakarta的包&#xff0c;看起来有点陌生。 很多时候&#xff0c;比较纠结不知道该导入哪一个包。 jakarta其实就是之前的javax。 主要JavaEE相关的&#xff0c;从之前javax名字也可以看出来&#xff0…

【AMD Xilinx】ZUBoard(2):通过AXI GPIO控制PL端的管脚输出

【AMD Xilinx】ZUBoard&#xff08;2&#xff09;&#xff1a;通过AXI GPIO控制PL端的管脚输出 一、基本功能和流程二、Vivado工程1. 总体框图2. AXI GPIO相关部分3. 配置AXI GPIO4. 绑定管脚4.1 根据原理图查找对应管脚4.1.1 LED04.1.2 LED1 4.2 I/O Planning 5. XDC 三、ARM代…

python+django游戏分享论坛网站49c2c

本系统主要包括管理员和用户两个角色组成&#xff1b;主要包括首页、个人中心、用户管理、游戏类型管理、游戏文章管理、交流论坛、系统管理等功能的管理系统。 系统权限按管理员和用户两类涉及用户划分。 &#xff08;1&#xff09;管理员功能需求 管理员登陆后&#xff0c;主…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

ESP32:整合存储配网信息和MQTT笔记

文章目录 1.给LED和KEY的所用IO增加配置项1.1 增加配置文件1.2 修改相应的c源码 2. 把mqtt\tcp的工程整合到一起2.1 在何处调用 mqtt_app_start() 3. 测试MQTT4. 完整的工程源码 有一段时间没有玩ESP32&#xff0c;很多知识点都忘记了。今天测试一下MQTT&#xff0c;做个笔记。…

Vue.js学习笔记(1)——Visual Studio Code搭建Vue.js框架

1 安装Node.js 1、下载安装包&#xff1a;进入官网&#xff08;https://nodejs.org/en&#xff09;&#xff0c;下载左侧的稳定版。 2、选择安装位置&#xff0c;不用勾选自动安装必要工具。 其他都默认Next。 配置环境&#xff0c;具体参考本文章&#xff1a; https://blo…

数据结构之树 --- 二叉树 < 堆 >

目录 1. 树是什么&#xff1f; 1.1 树的表示 2. 二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储结构 2.4.1 顺序存储 2.4.2 链式存储 3. 二叉树顺序结构的实现 <堆> 3.1 二叉树的顺序结构 ​编辑 3.2 堆的概念及结构 ​编辑…

啊?这也算事务?!

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

数据库开发之事务和索引的详细解析

2. 事务 场景&#xff1a;学工部整个部门解散了&#xff0c;该部门及部门下的员工都需要删除了。 操作&#xff1a; -- 删除学工部 delete from dept where id 1; -- 删除成功 ​ -- 删除学工部的员工 delete from emp where dept_id 1; -- 删除失败&#xff08;操作过程中…