当前位置: 首页 > news >正文

力扣每日一刷Day 19

Practice Day nineteen:Leetcode T 70

今天,我们来讲解动态规划中的最优子结构。

定义

如果一个问题的最优解包含其子问题的最优解,那么这个问题就具有最优子结构。换句话说,一个问题的最优解可以通过其子问题的最优解来构建。

 特征

  • 子问题的独立性:每个子问题的解是独立的,互不干扰。

  • 子问题的重叠性:在求解过程中,相同的子问题会被多次计算,动态规划通过存储这些子问题的解来避免重复计算。

应用

最优子结构是动态规划算法能够高效解决问题的基础。通过将问题分解为子问题,并存储子问题的解(通常使用一个表格),可以避免重复计算,从而大大提高算法的效率。

了解最优子结构后,我们就开始解答今天的题目吧

题目条件:阶梯数目、步长为1和2

题目目的:找到所给阶梯的所有方案组合数

事实上今天的是easy题,我们只拿他来理解思想,所以这是恰好的

今天我们依旧使用Leetcode的官方解答

我们知道:每做一次决定时,我们都有两种选择,两种选择为1和2(2可以拆为1和1,这实际上也算步长选取为1的一种情况,所以可以合并,故只有两种选择)。

那么我们的函数关系式可以被表示为:f(x)=f(x−1)+f(x−2)

其中x即为当前台阶编号,f(x) 表示爬到第 x 级台阶的方案数,事实上,每进行一次步进时,都可以把当前台阶序号看作最后的台阶序号,所以这个公式对最后一级台阶也是适用的。

是的,也许你会疑惑:为什么不是f(x)=f(x−1)+1+f(x−2)+1?以符合我们上面所说的,只有两种选择,每做出一种选择,方案数目就加上1?

哈哈,要像这样写f(x)=f(x−1)+1+f(x−2)+1的话,那当然也可以,但是这样未免不够美观,而且每次都需要进行额外的加2,这显然会造成算法效率的降低。如果是按这样来,我们初始化时的时候,从第零阶开始f(0)=0。

若是按f(x)=f(x−1)+f(x−2)这样来,我们的f(0)=1。可以见到,两种不同的公式,只是缘于初始化时赋的值不同。如果按f(0)=1来,每次调用f(x)时,就已经加上1了,这个1由f(0)=1提供,所以不必每次调用f(x)都像一样f(x)=f(x−1)+1+f(x−2)+1分别加上1。

你无法反驳,显然f(x)=f(x−1)+f(x−2)更加美观与迅速,不是吗?

完成了对于公式的理解后,我们需要理解f(0)的初值设置。如果你认为,f(0)到f(0)本身也算一种方案,以符合(x)=f(x−1)+f(x−2)的运行逻辑,那就应该让f(0)=1。

如果你不认为f(0)到f(0)本身不是一种方案,那他就应该符合f(x)=f(x−1)+1+f(x−2)+1的逻辑。

完成了对于公式的构建与初值的选择后,我们来进行代码的构建

由于他超简单的,所以我一次性把完整代码放出来了。

时间复杂度:O(n)

空间复杂度:O(1)

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;}
};

由于我们只需要记录最终的方案数,且后面的计算无需查询更遥远的结果,所以我们不需要完整的容器来记录所有变量,只需要p和q,就可以分别存储f(i-1)和f(i-2)这些中间变量。

对于输出的结果,我们只需要利用一个变量 r 就可以完成对结果的储存。

对于上面的操作,他有个名称,叫做滚动数组。这是一个很有意思的数据结构,官方题解中有动画演示,没有了解过的小伙伴可以看一看,链接我会按照惯例放到题解的最后。

对于滚动数组的实现,我们通过注释来理解他

 p = q; q = r; r = p + q;
/*设当前进行的台阶序号为i*/
/*第一行的 p 代表i-2的阶梯方案数,即f(i-2)*/
/*第一行的 q 代表的是i-2的方案数,即f(i-2),这是因为进入下一台阶序号后, q 的值仍未得到更新,记录的是上一个台阶序号的方案数f(i-1),而进入下一台阶序号后,台阶编号由i-1变为i-2,故此时q记录的值是
f(i-2)*//*第二行的 q 是将上一个台阶序号的方案数,即f(i-1),赋值给q*/
/*第二行的 r 是上一个台阶的方案数*//*求当前台阶序号的方案数,即 r=f(i)=f(i-2)=p + f(i-1)=q*/

最后返回一个答案 r ,没什么好说的。

作者:力扣官方题解

链接:https://leetcode.cn/problems/climbing-stairs/solutions/286022/pa-lou-ti-by-leetcode-solution/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

http://www.dtcms.com/a/360758.html

相关文章:

  • RK3399内核驱动实战:获取设备号控制LED的四种方法(由浅入深、代码注释详尽)
  • 【CMake】Ctest,Cpack
  • 电子电气架构 --- 智能电动车EEA电子电气架构(上)
  • Linux | 走进网络世界:MAC、IP 与通信的那些事
  • 【macOS】垃圾箱中文件无法清理的--特殊方法
  • 深度学习跨领域应用探索:从技术落地到行业变革
  • 华为eNSP防火墙综合网络结构训练.docx
  • npm 打包上传命令,撤销错误版本
  • 山东省信息技术应用创新开展进程(一)
  • 设计模式13-迭代器模式
  • OS+MySQL+(其他)八股小记
  • 【lucene】 中的impactsenum与impactsdisi有啥区别?
  • 开源npm引导guide组件
  • 基于.NET Framework 4.0的FTP文件传输类
  • 基于Hadoop的可视化城市宜居指数分析(代码+数据库+LW)
  • 【macOS】垃圾箱中文件无法清理的常规方法
  • Mac上如何安装mysql
  • MIT 6.5840 (Spring, 2024) 通关指南——Lab 2: Key/Value Server
  • 【Docker】Docker容器和镜像管理常用命令
  • Spring Bean 生命周期中的 @PostConstruct 注解
  • TCP实现线程池竞争任务
  • LeetCode Hot 100 Python (31~40)
  • 运动规划实战案例 | 基于行人社交模型的移动机器人动态避障(附ROS C++仿真)
  • Linux Tun/Tap 多队列技术
  • 【STM32】贪吃蛇 [阶段2](嵌入式进阶方向)
  • 【含文档+PPT+源码】基于SpringBoot+微信小程序的饮水健康之净水器保养管理系统设计与实现【包运行成功】
  • 【Linux】模拟实现Shell(下)
  • 打开模板打印
  • Ajax笔记(下)
  • 《探索C++11:现代C++语法的性能革新(上篇)》