动态规划详解

2023-05-16

动态规划的入门,一般是从斐波拉契数列开始。该数列由0和1开始,后面的每一项数字都是前面两项数字的和,定义如下:

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

给定一个n,要求F(n),用递归方法可以很容易地解决这个问题,代码如下:

def fib(self, n: int) -> int:
    if n == 0 or n == 1:
        return n
    return fib(n-1) + fib(n-2)

然而,上面的递归方法会造成大量重复计算,因为有很多重复子问题,时间复杂度为O(2^n)。例如,在求f(5)时,需要先求子问题f(4)和f(3)。递归地求f(4)时,又要先求子问题f(3)和f(2),这里的f(3)与求f(5)时的子问题就重复了。

为了解决这个问题,我们就想到一个方法:如果我们每次都把结果保存下来,复杂度就会大大降低。能不能让每个重复的子问题都只计算一次,即每个F(n)都只计算一次。这就是动态规划的核心思想:

  1. 将原问题分解成一系列子问题
  2. 每个子问题只求解一次,保存到一个状态数组dp[]

用动态规划来解斐波拉契数列:

def fib(self, n: int) -> int:
    if n == 0 or n == 1:
        return n
    dp = [0] * (n+1)
    dp[0] = 0
    dp[1] = 1
    for i in range(2, n+1):    
        dp[i] = dp[i-1] + dp[i-2]
    return dp[n]

将时间复杂度由O(2^n)降低到了O(n),真香!


如果看了上面的内容,你还是云里雾里,那么:

很正常

理解了dp的思想,也不一定会刷题,下面分享一套自己的刷题模板。首先来看一个经典的爬楼梯问题:

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

前面说了动态规划的核心思想,是把一个问题分解成许多个不互相重合的子问题。对于这个爬楼梯问题,我们需要怎么开始分解呢?

一个很好的方法是,先找到最后一步的解决方法,即得到最终答案的前一步。对于这个例子,最后一步爬完楼梯之后会到达顶楼。那么要到达顶楼、最后一步应该是什么呢?

很显然,由于每次只能爬一个或者两个台阶,那么到达顶楼之前,要么在倒数第一层,最后爬一个台阶登顶。要么在倒数第二层,最后爬两个台阶登顶。这样问题就分解成了:

到达顶楼的方法 = 到达倒数第一层的方法 + 到达倒数第二层的方法

这样就可以自顶向下递推,用dp[i]来表示到达第i层的方法,写成伪代码:

    dp[i] = dp[i-1] + dp[i-2]

这里再回顾一下前面,为什么递归的时间复杂度非常爆炸?

因为计算dp[i]的时候需要计算一次dp[i-2],计算dp[i-1]的时候,由于dp[i-1] = dp[i-2] + dp[i-3],也需要计算一次dp[i-2],这里就重复了,学过编程的人都知道,递归里的重复是非常恐怖的。

回过来,dp[]数组叫做状态数组,目的是保存之前每一次计算的值。既然计算后面的值需要用到前面的值,那么就肯定是从前面开始计算,即自底向上。

到这里,大家都应该发现了,我们将问题从递归的自顶向下、变成了动态规划的自底向上,从而降低了复杂度。即:

 递归       ->      动态规划
  ||                  ||
自顶向下     ->      自底向上

那么爬楼梯问题的的动态规划解应该为:

def climbStairs(self, n: int) -> int:
    if n == 1:
        return 1
    dp = [0]*(n+1)
    dp[0] = 0
    dp[1] = 1
    dp[2] = 2
    for i in range(3, n+1):
        dp[i] = dp[i-1] + dp[i-2]
    return dp[n]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态规划详解 的相关文章

  • 代码覆盖率工具OpenCppCoverage在Windows上的使用

    OpenCppCoverage是用在Windows C 43 43 上的开源的代码覆盖率工具 xff0c 源码地址为https github com OpenCppCoverage OpenCppCoverage xff0c 最新发布版本为
  • nerfstudio介绍及在windows上的配置、使用

    nerfstudio提供了一个简单的API xff0c 可以简化创建 训练和可视化NeRF的端到端过程 该库通过模块化每个组件来支持可解释的NeRF实现 nerfstudio源码地址 https github com nerfstudio
  • Qt中QDebug的使用

    QDebug类为调试信息 debugging information 提供输出流 它的声明在 lt QDebug gt 中 xff0c 实现在Core模块中 将调试或跟踪信息 debugging or tracing information
  • OkHttpUtil

    package com example someutil util import com google gson Gson import java util Iterator import java util Map import java
  • Sourcetree介绍及使用

    Sourcetree是一个操作简单但功能强大的免费Git客户端管理工具 xff0c 可应用在Windows和Mac平台 Sourcetree的安装 xff1a 1 从Sourcetree Free Git GUI for Mac and W
  • C++14中lambda表达式新增加的features的使用

    lambda表达式是在C 43 43 11中引入的 xff0c 它们可以嵌套在其它函数甚至函数调用语句中 xff0c C 43 43 11中lambda表达式的使用参考 xff1a https blog csdn net fengbingc
  • OpenSSL简介及在Windows、Linux、Mac系统上的编译步骤

    OpenSSL介绍 xff1a OpenSSL是一个强大的安全套接字层密码库 xff0c 囊括主要的密码算法 常用的密钥和证书封装管理功能及SSL协议 xff0c 并提供丰富的应用程序供测试或其它目的使用 SSL是SecureSockets
  • 信息安全领域相关术语介绍

    一 SSL 安全套接字层 SSL Secure Sockets Layer 是一种协议 xff0c 支持服务通过网络进行通信而不损害安全性 它在客户端和服务器之间创建一个安全连接 然后通过该连接安全地发送任意数据量 SSL最初是用来保障数据
  • 对称加密算法之DES介绍

    DES Data Encryption Standard 是分组对称密码算法 DES采用了64位的分组长度和56位的密钥长度 xff0c 它将64位的输入经过一系列变换得到64位的输出 解密则使用了相同的步骤和相同的密钥 DES的密钥长度为
  • OpenSSL中对称加密算法DES常用函数使用举例

    主要包括3个文件 xff1a 1 cryptotest h ifndef CRYPTOTEST H define CRYPTOTEST H include lt string gt using namespace std typedef e
  • 对称加密算法之RC4介绍及OpenSSL中RC4常用函数使用举例

    RC4是一种对称密码算法 xff0c 它属于对称密码算法中的序列密码 streamcipher 也称为流密码 xff0c 它是可变密钥长度 xff0c 面向字节操作的流密码 RC4是流密码streamcipher中的一种 xff0c 为序列
  • 摘要算法之MD5介绍及OpenSSL中MD5常用函数使用举例

    MD5 Message DigestAlgorithm 5 是计算机中广泛使用的杂凑算法之一 主要可以实现将数据运算后转换为一串固定值 xff0c 其前身主要有MD2 MD3和MD4算法 MD2算法在1989年由Rivest设计开发 xff
  • 非对称加密算法之RSA介绍及OpenSSL中RSA常用函数使用举例

    RSA算法 xff0c 在1977年由Ron Rivest Adi Shamirh和LenAdleman xff0c 在美国的麻省理工学院开发完成 这个算法的名字 xff0c 来源于三位开发者的名字 RSA已经成为公钥数据加密标准 RSA属
  • 有效的rtsp流媒体测试地址汇总

    以下是从网上搜集的一些有效的rtsp流媒体测试地址 xff1a 1 rtsp 218 204 223 237 554 live 1 0547424F573B085C gsfp90ef4k0a6iap sdp 2 rtsp 218 204 2
  • Flask【第十章】:特殊装饰器 @app.before_request 和 @app.after_request 以及@app.errorhandler...

    特殊装饰器 64 app before request 和 64 app after request以及 64 app errorhandler 一 背景 xff1a Flask我们已经学习很多基础知识了 现在有一个问题 我们现在有一个 F
  • Linux Socket基础介绍

    Linux Socket函数库是从Berkeley大学开发的BSD UNIX系统中移植过来的 BSD Socket接口是众多Unix系统中被广泛支持的TCP IP通信接口 xff0c Linux下的Socket程序设计 xff0c 除了微小
  • libcurl库的使用(通过libcurl库下载url图像)

    1 从http curl haxx se download html下载libcurl源码 xff0c 解压缩 xff1b 2 通过CMake cmake gui 生成vs2013 x64位 CURL sln xff1b 3 打开CURL
  • 人工神经网络简介

    本文主要对人工神经网络基础进行了描述 xff0c 主要包括人工神经网络的概念 发展 特点 结构 模型 本文是个科普文 xff0c 来自网络资料的整理 一 人工神经网络的概念 人工神经网络 xff08 Artificial Neural Ne
  • 卷积神经网络(CNN)基础介绍

    本文是对卷积神经网络的基础进行介绍 xff0c 主要内容包括卷积神经网络概念 卷积神经网络结构 卷积神经网络求解 卷积神经网络LeNet 5结构分析 卷积神经网络注意事项 一 卷积神经网络概念 上世纪60年代 xff0c Hubel等人通过
  • C++中struct的使用

    C 43 43 语言继承了C语言的struct xff0c 并且加以扩充 在C语言中struct是只能定义数据成员 xff0c 而不能定义成员函数的 而在C 43 43 中 xff0c struct类似于class xff0c 在其中既可以

随机推荐

  • Windows与Linux之间互传文件的方法

    以下方法均是以Windows为操作机 xff1a 1 通过WinSCP WinSCP是一款开源的SFTP客户端 xff0c 运行于Windows系统下 xff0c 遵照GPL发布 WinSCP除了SFTP xff0c 还支持SSH SCP
  • 非对称加密算法RSA公钥私钥的模数和指数提取方法

    生成非对称加密算法RSA公钥 私钥的方法 xff1a 1 通过OpenSSL库生成 xff0c 可参考 https github com fengbingchun OpenSSL Test blob master demo OpenSSL
  • Base64简介

    Base64是一种基于64个可打印字符来表示二进制数据的表示方法 由于2 6 61 64 xff0c 所以每6个比特为一个单元 xff0c 对应某个可打印字符 3个字节有24个比特 xff0c 对应于4个Base64单元 xff0c 即3个
  • HTTP协议简介

    HTTP HyperText Transfer Protocol 超文本传输协议 xff1a 是一种用于分布式 协作式和超媒体信息系统的应用层协议 HTTP是万维网的数据通信的基础 设计HTTP最初的目的是为了提供一种发布和接收HTML页面
  • HTTPS协议简介

    HTTPS HyperText Transfer Protocol Secure 超文本传输安全协议 xff1a 是一种透过计算机网络进行安全通信的传输协议 HTTPS经由HTTP进行通信 xff0c 但利用SSL TLS来加密数据包 HT
  • base64开源库介绍及使用

    网上有一些开源的base64编解码库的实现 xff0c 下面介绍几个 xff1a cppcodec是一个仅包括头文件的C 43 43 11库 xff0c 用于编解码RFC 4648中指定的base64 base64url base32 ba
  • Ubuntu下使用CMake编译OpenSSL源码操作步骤(C语言)

    OpenSSL的版本为1 0 1g xff0c 在ubuntu下通过CMake仅编译c代码不包括汇编代码 xff0c 脚本内容如下 xff1a build sh内容 xff1a bin bash real path 61 realpath
  • ImageNet图像数据集介绍

    ImageNet图像数据集始于2009年 xff0c 当时李飞飞教授等在CVPR2009上发表了一篇名为 ImageNet A Large Scale Hierarchical Image Database 的论文 xff0c 之后就是基于
  • 网络文件系统(NFS)简介

    网络文件系统 Network File System NFS 是一种分布式文件系统协议 xff0c 最初由Sun Microsystems公司开发 xff0c 并于1984年发布 其功能旨在允许客户端主机可以像访问本地存储一样通过网络访问服
  • 实时流协议(RTSP)简介

    RTSP Real Time Streaming Protocol xff0c RFC2326 xff0c 实时流传输协议 xff0c 是TCP IP协议体系中的一个应用层协议 xff0c 由哥伦比亚大学 网景 Netscape 和Real
  • 远程过程调用RPC简介

    RPC Remote Procedure Call 远程过程调用 xff1a 是一种通过网络从远程计算机程序上请求服务 xff0c 而不需要了解底层网络技术的思想 RPC是一种技术思想而非一种规范或协议 xff0c 常见RPC技术和框架有
  • C语言中头文件包含的处理原则

    很多事不深入以为自己懂了 xff0c 但真正用到项目上 xff0c 才发现了问题 曾以为自己写C语言已经轻车熟路了 xff0c 特别是对软件文件的工程管理上 xff0c 因为心里对自己的代码编写风格还是有自信的 毕竟刚毕业时老大对我最初的训
  • Unity3D物体自动躲避障碍物

    Unity版本 2017 4 4f1 基本思路 物体向前发射一个射线 xff0c 检测到碰撞后 xff0c 根据碰撞信息选择新的方向 最终结果如下 具体实现步骤代码 1 物体添加胶囊体碰撞组件CapsuleCollider 通过发射虚拟胶囊
  • nginx的请求接收流程(二)

    在ngx http process request line函数中 xff0c 解析完请求行之后 xff0c 如果请求行的uri里面包含了域名部分 xff0c 则将其保持在请求结构的headers in成员的server字段 xff0c h
  • C++学习_udp协议(socket)的封装

    C 43 43 学习笔记 xff0c UDP socket 协议的封装实现 1 配置QT下的pro文件 1 TEMPLATE 61 app 2 CONFIG 43 61 console 3 CONFIG 61 app bundle 4 CO
  • 西门子PLC学习笔记一(S7-300简介)

    使用了Step7有几天了 xff0c 现在系统的学习一下 xff0c 现记录一下学习的内容 1 S7 300硬件结构 S7 300或者S7 400的PLC是模块式的PLC xff0c 各种模块式相互独立的 xff0c 分别安装在机架上 硬件
  • 外网访问树莓派服务器(自购域名+Sakura Frp内网穿透)

    首先在域名代理商 xff08 如腾讯云 xff09 购买一个喜欢的域名 注册Sakura Frp账号 xff0c 进入管理面板后 xff0c 创建隧道 xff0c 服务器选择可建站类型的 xff0c 隧道类型为HTTP xff0c 本地地址
  • Python删除全部已安装的pip包

    pip freeze span class token operator gt span allpackages txt pip uninstall r allpackages txt y
  • Vue父组件主动获取子组件的值和方法

    在父组件使用子组件的代码中 xff0c 为子组件加上ref 61 34 name 自己设置一个名称 34 然后在代码中 xff1a span class token keyword this span span class token pu
  • 动态规划详解

    动态规划的入门 xff0c 一般是从斐波拉契数列开始 该数列由0和1开始 xff0c 后面的每一项数字都是前面两项数字的和 xff0c 定义如下 xff1a F 0 61 0 F 1 61 1 F n 61 F n 1 43 F n 2 其