动态规划感悟1

news/2025/3/23 1:01:03/

下面的感悟主要还是基于力扣上面动态规划(基础版)得出来的相关的做题结论

动态规划(基础版) - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

首先是

斐波那契类型的动态规划
70. 爬楼梯 - 力扣(LeetCode)

主要的方法就是需要知道下面的公式
f ( x ) = f ( x − 1 ) + f ( x − 2 ) f(x)=f(x−1)+f(x−2) f(x)=f(x1)+f(x2)
也就是说爬到第 x 级台阶的方案数是爬到第 x−1 级台阶的方案数和爬到第 x−2 级台阶的方案数的和。然后就是确定边界条件:我们是从第 0 级开始爬的,所以从第 0 级爬到第 0 级我们可以看作只有一种方案,即 f(0)=1;从第 0 级到第 1 级也只有一种方案,即爬一级,f(1)=1。

后面的快速矩阵幂和公式法可以看官方的题解

// 这段代码的时间复杂度是最低的
class Solution
{
public:int climbStairs(int n){vector<int> dp(n + 1, 0);dp[0] = 1;dp[1] = 1;for (int i = 2; i < n + 1; i++)dp[i] = dp[i - 1] + dp[i - 2];return dp[n];}
};
// 时间复杂度比较的高,空间复杂度还是比上面的代码好一点
class Solution
{
public:int climbStairs(int n){int a = 1, b = 1, temp;for (int i = 1; i < n; i++){temp = a;a = b;b = b + temp;}return b;}
};

509. 斐波那契数 - 力扣(LeetCode)

和爬楼梯是一样的解法

class Solution
{
public:int fib(int n){if (n == 0)return 0;if (n == 1)return 1;vector<int> dp(n + 1, 0);dp[0] = 0;dp[1] = 1;for (int i = 2; i < n + 1; i++)dp[i] = dp[i - 1] + dp[i - 2];return dp[n];}
};

1137. 第 N 个泰波那契数 - 力扣(LeetCode)

是上面两道题目的变体,需要确定如下的递推关系:
T ( n ) = T ( n − 1 ) + T ( n − 2 ) + T ( n − 3 ) T(n)=T(n−1)+T(n−2)+T(n−3) T(n)=T(n1)+T(n2)+T(n3)

class Solution
{
public:int tribonacci(int n){if (n == 0)return 0;if (n == 1 || n == 2)return 1;vector<int> dp(n + 1, 0);dp[0] = 0;dp[1] = 1;dp[2] = 1;for (int i = 3; i < n + 1; i++)dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];return dp[n];}
};

746. 使用最小花费爬楼梯 - 力扣(LeetCode)

要想使用动态规划,主要是需要确定好状态转移方程。不妨以dp[i]表示达到下标i的最小花费。

则dp[0]=dp[1]=0,这是边界条件。

当 2≤i≤n 时,可以从下标 i−1 使用 cost[i−1] 的花费达到下标 i,或者从下标 i−2 使用 cost[i−2] 的花费达到下标 i。为了使总花费最小,dp[i] 应取上述两项的最小值,因此状态转移方程如下:

d p [ i ] = m i n ( d p [ i − 1 ] + c o s t [ i − 1 ] , d p [ i − 2 ] + c o s t [ i − 2 ] ) dp[i]=min(dp[i−1]+cost[i−1],dp[i−2]+cost[i−2]) dp[i]=min(dp[i1]+cost[i1],dp[i2]+cost[i2])
然后在进行计算,可以最终求出来dp[n]的最小花费出来。

当然,注意到当 i≥2 时,dp[i] 只和 dp[i−1] 与 dp[i−2] 有关,因此可以使用滚动数组的思想,将空间复杂度优化到 O(1)。

// 时间复杂度和空间复杂度都是O(n)
class Solution
{
public:int minCostClimbingStairs(vector<int> &cost){int length = cost.size();if (length == 0)return 0;if (length == 1)return cost[0];if (length == 2)return min(cost[0], cost[1]);vector<int> dp(length + 1, 0);for (int i = 2; i < length + 1; i++)dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);return dp[length];}
};// 使用滚动数组
class Solution
{
public:int minCostClimbingStairs(vector<int> &cost){int n = cost.size();int prev = 0, curr = 0; // prev代表指向curr的前一个位置for (int i = 2; i <= n; i++){int next = min(curr + cost[i - 1], prev + cost[i - 2]);prev = curr;curr = next;}return curr;}
};

198. 打家劫舍 - 力扣(LeetCode)

用dp[i]表示前i间房屋能偷窃到的最高总金额,那么就有如下的状态转移方程:
d p [ i ] = m a x ( d p [ i − 2 ] + n u m s [ i ] , d p [ i − 1 ] ) dp[i]=max(dp[i−2]+nums[i],dp[i−1]) dp[i]=max(dp[i2]+nums[i],dp[i1])
边界条件为:
{ d p [ 0 ] = n u m s [ 0 ] 只有一间房屋,则偷窃该房屋 d p [ 1 ] = max ⁡ ( n u m s [ 0 ] , n u m s [ 1 ] ) 只有两间房屋,选择其中金额较高的房屋进行偷窃 \ \begin{cases} dp[0] &= nums[0] & \quad &\text{只有一间房屋,则偷窃该房屋} \\ dp[1] &= \max(nums[0], nums[1]) & &\text{只有两间房屋,选择其中金额较高的房屋进行偷窃} \end{cases} \  {dp[0]dp[1]=nums[0]=max(nums[0],nums[1])只有一间房屋,则偷窃该房屋只有两间房屋,选择其中金额较高的房屋进行偷窃 

// 比较的复杂,但是能够通过
class Solution
{
public:int rob(vector<int> &nums){int length = nums.size();if (length == 0)return 0;if (length == 1)return nums[0];if (length == 2)return max(nums[0], nums[1]);if (length == 3)return max(nums[0] + nums[2], nums[1]);nums[2] = nums[2] + nums[0];int maxm = nums[2];for (int i = 3; i < length; i++){nums[i] += max(nums[i - 2], nums[i - 3]);maxm = max(maxm, nums[i]);}return maxm;}
};// 下面的方法是比较的好的
class Solution
{
public:int rob(vector<int> &nums){int length = nums.size(); // 用来记录数组的长度if (length == 0)return 0;if (length == 1)return nums[0];nums[1] = max(nums[0], nums[1]); // nums[1]用来记录的是前2间房子能够获得的最大金额for (int i = 2; i < length; i++)nums[i] = max(nums[i - 2] + nums[i], nums[i - 1]);return nums[length - 1];}
};// 当然,也是可以使用滚动数组进行求解的。
class Solution {
public:int rob(vector<int>& nums) {int len = nums.size();if (len == 0)return 0;if (len == 1)return nums[0];nums[1] = max(nums[0], nums[1]);int first = nums[0], second = nums[1]; // first始终指向second左侧for (int i = 2; i < len; i++) {int temp = max(nums[i] + first, second);first = second;second = temp;}return second;}
};

http://www.ppmy.cn/news/1581261.html

相关文章

模型空间、图纸空间、布局(Layout)之间联系——CAD c#二次开发

在 AutoCAD 的二次开发中&#xff0c;**模型空间&#xff08;Model Space&#xff09;**、**图纸空间&#xff08;Paper Space&#xff09;** 和 **布局&#xff08;Layout&#xff09;** 是三个核心概念&#xff0c;它们的关系及开发中的操作逻辑如下&#xff1a; --- 1. 模…

JVM(Java虚拟机)的核心组成

1. 类加载器&#xff08;Class Loader&#xff09; 功能&#xff1a;负责将.class文件加载到内存&#xff0c;并转换为JVM可识别的数据结构。 分类&#xff1a; 启动类加载器&#xff08;Bootstrap Class Loader&#xff09;&#xff1a;加载JAVA_HOME/lib下的核心类库&#x…

SQL Server 2014 (x64) 中文版安装与使用指南(附安装包)

SQL Server 2014 (x64) - CHS 是 Microsoft SQL Server 2014 的中文版&#xff0c;适用于 64 位操作系统。以下是关于该版本的一些关键信息&#xff1a; SQL Server 2014 (x64)安装装包下载地址链接&#xff1a;https://pan.quark.cn/s/a5d01527a246 1. 版本类型 CHS 表示中文…

【Node.js入门笔记9---path 模块】

Node.js入门笔记9 Node.js---path 模块一、核心功能0.学习path的前提1. 使用 path.join() 安全拼接路径2. path.resolve()&#xff0c;路径解析&#xff08;绝对路径&#xff09;3. 路径信息提取4. 路径规范化 二、跨平台关键点1. 路径分隔符2. 环境变量分隔符3. 路径格式解析4…

使用LangChain实现基于LLM和RAG的PDF问答系统

目录 前言一.大语言模型(LLM)1. 什么是LLM&#xff1f;2. LLM 的能力与特点 二、增强检索生成(RAG)三. 什么是 LangChain&#xff1f;1. LangChain 的核心功能2. LangChain 的优势3. LangChain 的应用场景4. 总结 四.使用 LangChain 实现基于 PDF 的问答系统 前言 本文将介绍 …

泰迪智能科技大模型开发平台与大模型应用平台介绍

大模型开发平台是一款面向高校大模型教学、科研的一站式大模型开发工具。平台能够自定义调用CPU和内存资源&#xff0c;自由配置专门针对大模型和深度学习等任务的硬件加速器&#xff08;如GPU或XPU&#xff09;&#xff0c;能够高效地执行大模型的prompt工程、大模型应用开发和…

【Linux】浅谈环境变量和进程地址空间

一、环境变量 基本概念 环境变量&#xff08;Environment Variables&#xff09;是操作系统提供的一种机制&#xff0c;用于存储和传递配置信息、系统参数、用户偏好设置等。 环境变量的作用 配置程序行为&#xff1a; 程序可以通过环境变量获取配置信息&#xff0c;例如日…

vue3父子组件传值

在 Vue 3 中&#xff0c;Composition API 是一种新的编写组件逻辑的方式&#xff0c;它通过 setup 函数提供了一种更灵活的方式来组织和复用代码。与传统的 Options API 相比&#xff0c;Composition API 更适合处理复杂的逻辑场景&#xff0c;尤其是在需要跨组件复用逻辑时。 …