Leetcode动态规划题解

news2024/11/18 8:40:17

第一题

509. 斐波那契数

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

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

给定 n ,请计算 F(n)

示例1:

输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3

思路

当我们写完回溯法的题目之后,看到这道题,第一个想法就是递归计算。

递归法

int fib(int n){
    return dfs(n);
}

int dfs(int n){
    if(n == 0){
        return 0;
    }

    if(n == 1){
        return 1;
    }
    return dfs(n - 1) + dfs(n - 2);
}

如果我们把递归树画出来,可以看到有重叠子问题

在这里插入图片描述

这是动态规划和普通穷举法的不同,也是动态规划的第一个要素。普通穷举法,子问题之间互不重叠,所以画出来递归树也没有相同的节点;动态规划,子问题之间有重叠,所以画出来的递归树有相同节点。既然递归树有相同节点,那我们就可以通过剪枝来优化算法。我们可以用一个数组来记录节点,如果某个节点已经被记录在数组中,那就直接返回数组中的值,而不用进行递归求解。

递归法+dp数组

int fib(int n){
    int[] dp = new int[n + 1];
    return dfs(n, dp);
}

int dfs(int n, int[] dp){
    if(n == 0){
        return 0;
    }

    if(n == 1){
        return 1;
    }

    if(dp[n] != 0){
        return dp[n];
    }

    dp[n] = dfs(n - 1, dp) + dfs(n - 2, dp);
    return dp[n];
}

这个时候我们再把递归树画出来,可以看到我们将递归树剪枝成了递归链表。

请添加图片描述

不难看出,现在问题转换成如何填充dp数组,我们可以对此继续进行优化。

迭代法(动态规划)

为了节省空间,我们可以放弃递归函数,用迭代循环的方式填充dp数组。

int fib(int n){
    if(n < 2){
        return n;
    }
    int[] dp = new int[n + 1];
    dp[0] = 0;
    dp[1] = 1;
    for(int i = 2; i <= n; i++){
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

总结

动态规划与穷举法的联系与区别:

动态规划有重叠子问题

动态规划三要素:

  1. 原问题可以拆解成重叠子问题

  2. 原问题的最优解由子问题的最优解构成

  3. 子问题到原问题有递推公式(状态转移方程)

第一条已经说明过了,后两条之后再说明。

动态规划解题步骤:

  1. 画出搜索树

  2. 确定搜索树节点的含义

  3. 确定搜索树节点连线的含义

  4. 确定dp数组的含义

  5. 列出递推公式

  6. 验证递推公式

后面详细说明这些解题步骤。

第二题

70. 爬楼梯

题目描述:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例1:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

思路

借这道题,我们来好好讲讲动态规划解题步骤。

第一步,画出搜索树。

请添加图片描述

我们设定从0阶开始登楼梯,需要n阶才能到达楼顶,也就是需要从0阶开始爬到n阶。

看搜索树,到达第3阶有两种方法。第一种方法,先到达第2阶,然后再向上爬1阶。第二种方法,先到达第1阶,再向上爬2阶。

到达第2阶,也有两种方法。第一种方法,先到达第1阶,然后再向上爬1阶。第二种方法,先到达第0阶,再向上爬2阶。

到达第1阶,只有一种方法,先到达第0阶,再向上爬1阶。

第0阶,也就是出发的台阶,每次都从第0阶出发。

第二步,确定搜索树节点的含义。

刚刚的搜索树只是登楼梯的示意图,每个节点表示的是“所在的台阶”,3表示第3阶,2表示第2阶。现在,要把“到达该台阶的方法”也添加到节点上,搜索树如下。

请添加图片描述

现在,用节点(0,1)表示之前的节点0,那么每个节点的含义就很明显了。第一个数表示在第0阶,第二个数表示到达第0阶的方法。显然的,一开始就在第0阶,那么到达第0阶的方法就1种。

节点(1,1)表示之前的节点1。到达第1阶的方法,只有从第0阶向上爬1阶,所以到达第1阶的方法就1种。

节点(2,2)表示之前的节点2。从图上看,到达第2阶有两种方法。第一种方法,先到达第1阶,然后再向上爬1阶。第二种方法,先到达第0阶,再向上爬2阶。所以,到达第2阶的方法=到达第1阶的方法+到达第0阶的方法。

同理,到达第3阶的方法=到达第2阶的方法+到达第1阶的方法。

第三步,确定搜索树节点连线的含义

很显然的,连线表示“向上爬的楼梯阶数”。每次可以选择向上爬1阶或2阶。

第四步,确定dp数组的含义。

从第二步确定节点的含义就可以看出,我们需要同时知道“所在的台阶”以及“到达该台阶的方法”才能解决问题。

用i来表示“所在的台阶”,i的范围为[0,n];用dp[i]来表示“到达第i阶的方法”。

第五步,列出递推公式。

从第二步可以看出,当i=0,1时,dp[i]=1;当i>1时,dp[i]=dp[i-1]+dp[i-2]。

所以递推公式如下

请添加图片描述

动态规划

经过上面的分析,最后我们得到了递推公式。现在,我们可以根据递推公式来填充dp数组。

class Solution {
    public int climbStairs(int n) {
        // 定义dp数组,i表示“所在的台阶”,dp[i]表示“到达第i阶的方法”。
        int[] dp = new int[n + 1]; 
        // 当i=0,1
        dp[0] = 1;
        dp[1] = 1;
        // 当i>1
        for(int i = 2; i <= n; i++){
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        // 返回“到达第n阶的方法”
        return dp[n];
    }
}

总结

我们用这道题,讲解了动态规划解题步骤。其中,最重要的就是画出搜索树,只要能够把搜索树画出来,然后把节点的含义和连线的含义搞清楚,就可以把节点转换成dp数组,把连线转换成递推公式。

下一题,将讲一下动态规划三要素。问题得先满足动态规划三要素,才能用动态规划的方法解题。

参考:

动态规划解题套路框架
算法设计与分析基础(第3版) (豆瓣)

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

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

相关文章

【计算机网络】计算机网络基础

计算机是人类社会不可或缺的工具&#xff0c;而单独的一台计算机的功能也是有限的&#xff0c;计算机需要和其它的设备相互连接通信形成的计算机网络才能对人类发展带来巨大的影响。 目录 计算机网络 通信协议 网络结构 网络边缘 接入网 网络核心 时延和吞吐量 时延 吞…

.Net Core6.0项目发布在IIS上访问404的问题

ASP.Net Core6.0项目发布在IIS上访问404的问题 进入线程池画面&#xff0c;将当前程序的线程池设为“无托管代码” 修改配置文件 Web.config&#xff0c;以下缺一不可 需要引用架包&#xff1a;Swashbuckle.AspNetCore.SwaggerUI.NetCore 6.0 自带集成了Swagger , 在发布项目时…

C++模板(函数模板、类模板)

目录 一、泛型编程 二、函数模板 函数模板概念 函数模板格式 函数模板的原理 函数模板的实例化 模板参数的匹配原则 三、类模板 类模板的定义格式 类模板的实例化 四、扩展 函数模板一定是推演&#xff1f;类模板一定是指定&#xff1f; 模板的分离编译 一…

MySQL高级【行级锁】

1&#xff1a;行级锁1.1&#xff1a;介绍行级锁&#xff0c;每次操作锁住对应的行数据。锁定粒度最小&#xff0c;发生锁冲突的概率最低&#xff0c;并发度最高。应用在 InnoDB存储引擎中。 InnoDB的数据是基于索引组织的&#xff0c;行锁是通过对索引上的索引项加锁来实现的&a…

WPF中Binding数据校验、并捕获异常信息的三种方式

Binding数据校验、并捕获异常信息的三种方式 WPF在使用Binding时&#xff0c;经常需要进行数据校验&#xff0c;如果校验失败需要捕获失败的原因&#xff0c;并加以展示&#xff0c;本文主要介绍数据校验异常并捕获的三种方式。 依赖属性异常捕获 先定义一个依赖属性 publi…

【Nacos】Nacos配置中心的使用与SpringCloud整合

在微服务架构中&#xff0c;当系统从一个单体应用&#xff0c;被拆分成分布式系统上一个个服务节点后&#xff0c;配置文件也必须跟着迁移&#xff08;分割&#xff09;&#xff0c;这样配置就分散了&#xff0c;不仅如此&#xff0c;分散中还包含着冗余。配置中心将配置从各应…

哪儿有微服务开源项目?

随着数字化时代的到来&#xff0c;微服务开源项目的应用价值逐渐凸显。作为提升企业办公协作效率的低代码开发平台项目&#xff0c;其表现出来的灵活性、易操作、简便的特性&#xff0c;成为现代化办公管理中的重要合作伙伴。我们今天一起来了解什么是微服务开源项目。 一、微服…

基于JavaWeb实现蜀南调味品商城物流配货系统

一、项目介绍 本文系统利用JavaWeb技术&#xff0c;设计和实现了连接公司、客户公司、物流运输为桥梁的销售配送管理系统&#xff0c;并以网络技术和信息技术在销售配送中的应用为重点&#xff0c;实现员工登录模块、员工信息管理模块、库存管理模块、订单处理模块、包装管理模…

高通Wi-Fi 7网络芯片方案IPQ9574,IPQ9554,IPQ9514,IPQ9570,IPQ9550,IPQ9510

networking pro 1620&#xff1a;芯片型号IPQ9574&#xff0c;支持4频段16路数据流&#xff0c;峰值速率33Gbps&#xff0c;支持4个2.5G口&#xff0c;1个5G口&#xff0c;1个万兆口&#xff1b;networking pro 1220&#xff1a;芯片型号IPQ9574&#xff0c;支持3频段12路数据流…

三个案例详解不同网段之间如何互通

当然还可以通过三层交换机划分VLAN配置更好。这里主要讲通过普通路由器之间互通一台路由器连接另外一台路由器&#xff0c;这两台路由器分别连接不同的网段&#xff0c;那么如果要这两个网段互通&#xff0c;则必须配置路由&#xff0c;这个就是静态路由。案例一、不同网段之间…

【练习】Day06

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录一、选择二、编程最小时间差答案1. 选择2. 编程普通小孩也要热爱生活&#xff01; 一、选择 散列技术中的冲突是指&#xff08; &#xff09; A. 两个元素具有相同的序号 B. 两个元素的键值不同&#xff0c;而其他…

Linux权限理解

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;linux当中对于权限的理解。 &#x1f490;一.生活中的权限 &#x1f338;二.Linux权限…

一文让你弄懂多租户数据库设计⽅案

文章目录前言一、设计方案二、方案剖析三、方案总结四、方案选型五、引申问题的解决方案六、写在最后前言 多租户是SaaS&#xff08;Software-as-a-Service&#xff09;下的一个概念&#xff0c;意思为软件即服务&#xff0c;即通过网络提供软件服务。 SaaS平台供应商将应用软…

微软的AD登录loginRedirect

我这边技术栈是reactts 如果你是vue&#xff0c;直接将tsx文件改成jsx就可以或者不该也没问题 上篇文章介绍了msal 的弹框登录&#xff0c;先介绍下重定向登录这个相对弹框登录要烦很多。。。中国内网看我查询的资料很少&#xff0c;只有微软系的公司才会有相对应的需求。此处自…

代码随想录算法训练营第二天|977.有序数组的平方 |209.长度最小的子数组 |59.螺旋矩阵II

977 有序数组平方 看完题后的思路 双指针 思路 本题如果使用暴力解法,需要按照绝对值将数组排序0(logn),然后进行平方.(或先平方,再排序,这样可以直接调用排序函数) 可以使用双指针法,定义两个指针,左指针是当前绝对值最小的负数,右指针是当前绝对值最小的整数,每一轮将较小…

03、openscenegraph(简称osg)源代码编译

通过上一节&#xff0c;我们准备下载好了osg源代码和依赖库&#xff0c;并安装了CMake、VS2013开发环境&#xff0c;接下来就可以进入编译工作了。 首先&#xff0c;将下载的openscenegraph源代码和依赖库3rdParty_VS2012.3_v110_x86_x64_V8b_full解压到同一个目录下&#xff…

构建系列之新一代利器Esbuild(下)

前言 本篇文章接上文&#xff0c;通过尝试使用esbuild的能力和业界的落地方案作为切入点继续深入esbuild的原理。 尝试Esbuild ESBuild在API层面上非常简洁, 主要的API只有两个: Transform和Build, 这两个API可以通过CLI, JavaScript, Go的方式调用 Transform主要用于对源代…

致而立之年的自己

&#xff08;点击即可收听&#xff09;时间是连续性的,人越长大,越能体会到,所谓的跨年与过年,其实是没有多大意义的但只要是人,就需要制造一些仪式感,弄出一些特殊的节日,用于安慰自己,对于逝去的曾今做一个告别,制造些记忆点然而,记忆这东西,是很容易健忘的,就像昨天,前天,吃…

泰克新2系示波器在微电网测试上的应用

直流微电网是由直流构成的微电网&#xff0c;是未来智能配用电系统的重要组成部分&#xff0c;对推进节能减排和实现能源可持续发展具有重要意义。相比交流微电网&#xff0c;直流微电网可更高效可靠地接纳风、直流逆变等分布式可再生能源发电系统、储能单元、电动汽车及其他直…

【C语言进阶】一万字教你实现简易通讯录管理

目录一. 通讯录要实现的功能1.项目文件分配2.通讯录基本功能二.test.c的实现1.逻辑代码的实现2.通讯录联系人信息的创建三.contacts.c的实现1.初始化通讯录2.添加联系人信息3.显示通讯录信息3.删除指定联系人信息4.查找指定联系人5.修改指定联系人信息6.以名字年龄排序通讯录7.…