【动态规划专栏】

动态规划基础知识

概念

        动态规划(Dynamic Programming,DP):用来解决最优化问题的算法思想。
        动态规划是分治思想的延伸,通俗一点来说就是大事化小,小事化无的艺术。
        一般来说,动态规划将复杂的问题分解为若干子问题,通过综合子问题的最优解来得到原问题的最优解。
        动态规划会将每个求解过的子问题记录下来,这样下次碰到相同的子问题,就可以直接使用之前记录的结果,而不重复计算。

特点

        最优子结构:动态规划将一个复杂的问题分解成若干个子问题,通过综合子问题的最优解来得到原问题的最优解。(“分”与“合”体现在 状态转移方程)其实有时候用动态规划也不一定就是最优解那种意思。
        重叠子问题:动态规划会将每个求解过的子问题的解记录下来,这样当下一次碰到同样的子问题时,就可以直接使用之前记录的结果,而不是重复计算。(虽然动态规划使用这种方式来提高计算效率,但不能说这种做法就是动态规划的核心)所谓记录就是dp数组。

写法

        递归,自顶向下(Top-down Approach),即从目标问题开始,将它分解成子问题的组合,直到分解至边界为至。
        递推,自底向上(Bottom-up Approach),即从边界开始,不断向上解决问题,直到解决了目标问题;
        适用场景:最大值/最小值, 可不可行, 是不是,方案个数

何时使用动态规划

        一个问题必须拥有重叠子问题和最优子结构,才能使用动态规划去解决。
核心套路:核心就是写出其状态转移方程(穷举);动态规划的本质,是对问题 状态的定义 和 状态转移方程的定义 ( 状态以及状态之间的递推关系 )

        下面给出动态规划中常用到的一些题目,希望能帮助大家成功掌握这门算法技术,分别为斐波那契类型、矩阵类型、动态规划在字符串的应用、最长递增子序列、最长公共子序列、动态规划在树种的应用、背包问题等等,如有错误,欢迎大家指出,谢谢!

        创作不易,点波关注再走呗~~~

斐波那契类型

1.1 爬楼梯(简单70. 爬楼梯)

1.1.1 题目描述

        假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

1.1.2 思路

1、动态规划第一点,先写出动态规划的推导公式

        假设f(x)表示表示爬到第 x级台阶的方案数,考虑最后一步可能跨了一级台阶,也可能跨了两级台阶,所以可以列举出以下式子

        f(x) = f(x-1)+f(x-2)

2、探索边界条件

        我们是从第 0级开始爬的,所以从第 0级爬到第0级我们可以看作只有一种方案,即 f(0)=1;从第 0级到第1级也只有一种方案,即爬一级,f(1)=1。

1.1.3 复杂度分析

时间复杂度:循环执行 n次,每次花费常数的时间代价,故时间复杂度为 O(n)。
空间复杂度:这里只用了常数个变量作为辅助空间,故空间复杂度为 O(1)。

1.1.4 代码

#include <iostream>
using namespace std;
class Solution {
public:int climbStairs(int n) {int p = 0, q = 0, r = 1;for (int i = 1; i <= n; ++i) {p = q; q = r; r = p + q;}return r;}
};
int main(){int n = 2;int res = Solution().climbStairs(n);cout  << res << endl;
}

1.2 斐波那契数(简单509. 斐波那契数)

1.2.1 题目描述

        斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

  • F(0) = 0,F(1) = 1
  • F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n) 。

输入:n=2 输出:1 ;  输入:n=3, 输出 3

1.2.2 思路

1、推导公式题目已经给出,F(n)=F(n-1)+F(n-2)

2、边界条件:F(0)和F(1);

3、此题优化的一个方向:使用滚动数组思想将空间复杂度优化成O(1)

1.2.3 复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

1.2.4 代码

#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:// 简单509: 斐波那契数int fib(int n) {if (n < 2) {return n;}int p = 0, q = 0, r = 1;for (int i = 2; i <= n; ++i) {p = q; q = r; r = p + q;}return r;}
};
int main()
{int n = 3;int res = Solution().fib(n);cout << res << endl;n = 4;res = Solution().fib(n);cout << res << endl;
}

1.3 打家劫舍(中等198. 打家劫舍)

1.3.1 题目描述

        你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

        给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

1.3.2 思路

这种比较复杂的动态规划,步骤可能比较麻烦了,可以分为四个解题步骤,如下所示:

  • 定义子问题
  • 写出子问题的递推关系
  • 确定DP数组的计算顺序
  • 空间优化(可选,非必须)

定义子问题

        原问题为从全部房子,将问题缩小为“从k个房间中能偷到的最大金额”,用f(k)表示;子问题包含参数k。假设共有n个房间,则有n个子问题。动态规划实际上就是通过求解一堆子问题的解来获得原问题的解。子问题常需要满足以下条件:

  • 原问题能由子问题表示。
  • 一个字问题的解能够通过其他子问题求解。例如本题中f(k)可以由f(k-1)和f(k-2)求出。

写出子问题的递推关系

        此题中,一共有n个房子,每个房子的金额分别是H0,H1,...,Hn-1,子问题f(k)表示从前k个房子中能偷到的最大金额,那么有两种偷法。

也就是f(k)=max{f(k-1),Hk-1+f(k-2)}; 边界条件为:f(0)=0,f(1)=H0

确定计算顺序

        在确定了子问题的递推关系之后,下一步就是依次计算出这些子问题了。在很多教程中都会写,动态规划有两种计算顺序,一种是自顶向下的、使用备忘录的递归方法,一种是自底向上的、使用 dp 数组的循环方法。不过在普通的动态规划题目中,99% 的情况我们都不需要用到备忘录方法,所以我们最好坚持用自底向上的 dp 数组。

        DP 数组也可以叫”子问题数组”,因为 DP 数组中的每一个元素都对应一个子问题。如下图所示,dp[k] 对应子问题 f(k),即偷前k间房子的最大金额。

        只要搞清楚了子问题的计算顺序,就可以确定 DP 数组的计算顺序。对于小偷问题,我们分析子问题的依赖关系,发现每个 f(k)依赖 f(k−1)和 f(k−2)。也就是说,dp[k] 依赖 dp[k-1] 和 dp[k-2]。

空间优化

空间优化的基本原理是,很多时候我们并不需要始终持有全部的 DP 数组。对于小偷问题,我们发现,最后一步计算 f(n)f(n)f(n) 的时候,实际上只用到了 f(n−1)f(n-1)f(n−1) 和 f(n−2)f(n-2)f(n−2) 的结果。n−3n-3n−3 之前的子问题,实际上早就已经用不到了。那么,我们可以只用两个变量保存两个子问题的结果,就可以依次计算出所有的子问题。

1.3.3 复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

1.3.4 代码

#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:int rob(vector<int> &nums){int prev = 0;int curr = 0;// 每次循环,计算“偷到当前房子为止的最大金额”for (int i : nums){// 循环开始时,curr 表示 dp[k-1],prev 表示 dp[k-2]// dp[k] = max{ dp[k-1], dp[k-2] + i }int temp = max(curr, prev + i);prev = curr;curr = temp;// 循环结束时,curr 表示 dp[k],prev 表示 dp[k-1]}return curr;}
};
int main()
{vector<int> nums = {1, 2, 3, 1};int res = Solution().rob(nums);cout << res << endl;nums = {2, 7, 9, 3, 1};res = Solution().rob(nums);cout << res << endl;
}

斐波那契类型的动态规划题目练习:

第N个泰波那契数 

删除并获得点数

矩阵类型的动态规划

2.1 中等62. 不同路径

链接:不同路径

2.1.1 题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?

示例2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

2.1.2 思路

1. 确定dp数组以及下标的含义:dp[i][j] 代表到达矩阵 [i,j] 位置总共具有多少条路径
2. 确定递推公式:到达 [i,j] 的路径总数 dp[i][j] 相当于由 dp[i-1][j]+向下移动一格 和 dp[i][j-1]+向右移动一格 组成。
        dp[i][j] = dp[i−1][j] + dp[i][j−1];
3. dp数组如何初始化:第0行和第0列都赋值为1
4. 确定遍历顺序:从前到后

5. 空间优化:由于dp[i][j]仅与第 i 行和第 i−1 行的状态有关,因此我们可以使用滚动数组代替代码中的二维数组,使空间复杂度降低为 O(n)。

2.1.3 复杂度分析

时间复杂度:O(mn)。

空间复杂度:O(min(m,n)),即为存储所有状态需要的空间。注意到 f(i,j)仅与第 i行和第 i−1 行的状态有关,因此我们可以使用滚动数组代替代码中的二维数组,使空间复杂度降低为 O(n)。此外,由于我们交换行列的值并不会对答案产生影响,因此我们总可以通过交换 m 和 n 使得 m≤n,这样空间复杂度降低至 O(min⁡(m,n))。

2.1.4 代码

class Solution {
public:int uniquePaths(int m, int n){vector<int> f(n, 1);for (int i = 1; i < m; ++i){for (int j = 1; j < n; ++j){f[j] += f[j - 1];}}return f[n - 1];}
};
int main()
{cout << Solution().uniquePaths(3, 7) << endl;cout << Solution().uniquePaths(3, 2) << endl;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

账单怎么记账软件下载,佳易王账单记账汇总统计管理系统软件教程

账单怎么记账软件下载&#xff0c;佳易王账单记账汇总统计管理系统软件教程 一、前言 以下软件以 佳易王账单记账汇总统计管理系统软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 软件特色&#xff1a; 1、功能实用&#xff0c;操作…

Vue之监测数据的原理(对象)

大家有没有想过&#xff0c;为什么vue可以监测到数据发生改变&#xff1f;其实底层借助了Object.defineProperty&#xff0c;底层有一个Observer的构造函数 让我为大家简单的介绍一下吧&#xff01; 我用对象为大家演示一下 const vm new Vue({el: "#app",data: {ob…

力扣hot100:42.接雨水

什么时候能用双指针&#xff1f; &#xff08;1&#xff09;对撞指针&#xff1a; ①两数和问题中可以使用双指针&#xff0c;先将两数和升序排序&#xff0c;可以发现规律&#xff0c;如果当前两数和大于target&#xff0c;则右指针向左走。 ②接雨水问题中&#xff0c;左边最…

基于STM32F4的FFT(快速傅里叶变换)求信号幅值,频率,相位差

基于STM32F4的FFT&#xff08;快速傅里叶变换&#xff09;求信号幅值&#xff0c;频率&#xff0c;相位差 一。FFT原理介绍 快速傅里叶变换&#xff08;Fast Fourier Transform&#xff0c;FFT&#xff09;是一种用于高效计算傅里叶变换的算法。傅里叶变换是一种信号处理技术…

动态规划|【双指针】|11.盛水最多的容器

题目 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xf…

发现了一个超级好用的上网神器!但是不知道在哪里有卖······随身WiFi好评推荐,随身WiFi好用吗?

这两天到一个小地方出差&#xff0c; 走到一个奶茶店附近&#xff0c; 突然老板打电话说一个紧急文件需要我处理&#xff0c; 说实话有点崩溃&#xff0c; 前不着村后不着店的&#xff0c; 我去哪里找网络办公 辛亏奶茶店的小姐姐听到了&#xff0c; 让我在她店里&#x…

LVS负载均衡服务器

简介: LVS (Linux Virtual Server):四层路由设备&#xff0c;是由中国人章文松研发的(阿里巴巴的副总裁)根据用户请求的IP与端口号实现将用户的请求分发至不同的主机。 工作原理: LVS工作在一台server上提供Directory(负载均衡器)的功能&#xff0c;本身并不提供服务&#xff…

【一起学习Arcade】(6):属性规则实例_约束规则和验证规则

一、约束规则 约束规则用于指定要素上允许的属性配置和一般关系。 与计算规则不同&#xff0c;约束规则不用于填充属性&#xff0c;而是用于确保要素满足特定条件。 简单理解&#xff0c;约束规则就是约束你的编辑操作在什么情况下可执行。 如果出现不符合规则的操作&#…

python实现有限域GF(2^8)上的乘法运算

有限域GF(2^8)上的乘法运算可以看成多项式的乘法 5e转换成二进制为0101 1110&#xff0c;对应的多项式为x^6x^4x^3x^2x 3f转换成二进制为0011 1111&#xff0c;对应的多项式为x^5x^4x^3x^2x1 将这两个多项式相乘再模多项式x^8x^4x^3x1得到结果为1110 0101&#xff0c;转换为…

C# 不可识别数据库格式问题

C#是一种流行的编程语言&#xff0c;用于开发各种类型的应用程序&#xff0c;包括与数据库交互的应用程序。然而&#xff0c;在处理数据库时&#xff0c;有时会遇到一些错误和问题。其中之一就是数据库格式不可识别的错误。 在C#中&#xff0c;我们通常使用ADO.NET来连接和操作…

Flink:动态表 / 时态表 / 版本表 / 普通表 概念区别澄清

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

使用query请求数据出现500的报错

我在写项目的时候遇到了一个问题&#xff0c;就是在存商品id的时候我将它使用了JSON.stringify的格式转换了&#xff01;&#xff01;&#xff01;于是便爆出了500这个错误&#xff01;&#xff01;&#xff01; 我将JSON.stringify的格式去除之后&#xff0c;它就正常显示了&…

源码框架-​1.Spring底层核心原理解析

目录 Spring中核心知识点: Bean的创建过程 推断构造方法 AOP大致流程 Spring事务 Spring中核心知识点: Bean的生命周期底层原理依赖注入底层原理初始化底层原理推断构造方法底层原理AOP底层原理Spring事务底层原理 ps:这篇文章中都只是大致流程&#xff0c;后续会针对每…

Linux工具篇

文章目录 1.yum1.1 yum是什么&#xff1f;1.2yum下载的软件包在哪&#xff1f;1.3 yum的配置1.4 yum的相关操作 2. Vim2.1 各种模式的相关操作2.2 利用vim解决普通用户无法sudo的问题2.3 vim的配置 3.gcc/g3.1 利用gcc理解程序的翻译过程3.2 编译器的自举 4. 程序的链接4.1动态…

3分钟,学会一个测试员必懂 Lambda 小知识!

今天再来给大家介绍下函数式接口和方法引用。 函数式接口 问&#xff1a;Lambda 表达式的类型是什么&#xff1f; 答&#xff1a;函数式接口 问&#xff1a;函数式接口是什么&#xff1f; 答&#xff1a;只包含一个抽象方法的接口&#xff0c;称为函数式接口 &#xff08;…

制作耳机壳的UV树脂耳机壳UV胶和塑料材质有什么不同?

制作耳机壳的UV树脂耳机壳UV胶和塑料材质有什么不同&#xff1f; 制作耳机壳的UV树脂和塑料材质在以下几个方面存在区别&#xff1a; 硬度与耐磨性&#xff1a;UV树脂具有较高的硬度和耐磨性&#xff0c;能够有效保护耳机内部零件&#xff0c;延长耳机使用寿命。而塑料材质相…

价格腰斩,腾讯云2024优惠活动云服务器62元一年,多配置报价

腾讯云服务器多少钱一年&#xff1f;62元一年起&#xff0c;2核2G3M配置&#xff0c;腾讯云2核4G5M轻量应用服务器218元一年、756元3年&#xff0c;4核16G12M服务器32元1个月、312元一年&#xff0c;8核32G22M服务器115元1个月、345元3个月&#xff0c;腾讯云服务器网txyfwq.co…

linux安装mysql5.7

linux安装mysql5.7 一、下载mysql5.7二、解压包介绍三、上传包到linux四、卸载mariadb五、安装mysql六、修改权限七、启动mysql八、使用过navicat创作不易&#xff0c;笔记不易&#xff0c;如觉不错&#xff0c;请三连&#xff0c;谢谢~~ 一、下载mysql5.7 去mysql官方下载&am…

数据结构题目①——数组

前言 本篇文章为博主进行代码随想录——数组练习后的总结会涉及到每一道题目的详细的思路整理&#xff0c;以及本人的易错点&#xff0c;希望对大家有所帮助 数组介绍&#xff1a; 数组在C语言中就已经有所涉及&#xff0c;它是一个最基础的数据结构&#xff0c;而在数据结构中…

Oracle 11g升级19c 后部分查询功能很慢

*Oracle 11g升级19c 后部分查询功能很慢 今天生产突然有个查询非常慢&#xff0c;日志显示执行了50秒左右&#xff0c;但是从日志中拿出SQL在PLSQL执行&#xff0c;发现用时不到1秒&#xff0c;查看SQL,怀疑是下面几种原因导致 1、使用函数不当 UNIT.UNIT_CODE LIKE CONCAT(‘…