动态规划,这将是你见过最详细的讲解

news2024/9/22 1:33:52

文章目录

  • 一、为什么要讲动态规划呢?
  • 二、什么是动态规划
  • 三、感受一下递归算法、备忘录算法、动态规划
    • 递归算法
    • 带备忘录的递归解法(自定向下)
    • 自底向上的动态规划
  • 四、动态规划的解题套路
    • 1. 穷举分析
    • 2. 确定边界
    • 3. 确定最优子结构
    • 4. 写出状态转移方程

我建议直接看下面的参考文章,因为大佬的讲解非常到位,我这里做的笔记肯定是没那么详细的,这里只是给我自己做个记录

看一遍就理解:动态规划详解
算法-动态规划 Dynamic Programming–从菜鸟到老鸟

一、为什么要讲动态规划呢?

我们刷leetcode的时候,经常会遇到动态规划类型题目。动态规划问题非常非常经典,也很有技巧性,一般大厂都非常喜欢问。学就要学一些回报最大的知识

二、什么是动态规划

动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题最优子结构性质的问题。

以上定义来自维基百科,看定义感觉还是有点抽象。简单来说,动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。

相信看到这里,我们可以知道动态规划也用到HashMap集合,如果还不会,请看我另一篇博客,让你秒懂Java集合框架

动态规划核心思想
动态规划最核心的思想,就在于拆分子问题,记住过往,减少重复计算。然而我认为记不记住过往不重要,重要的是不要重复计算子问题就行了。例如自顶向下就需要备忘录,自底向上就不需要备忘录了。
在这里插入图片描述
我们来看下,网上比较流行的一个例子

A : “1+1+1+1+1+1+1+1 =?”
A : “上面等式的值是多少”
B : 计算 “8”
A : 在上面等式的左边写上 “1+” 呢?
A : “此时等式的值为多少”
B : 很快得出答案 “9”
A : “你怎么这么快就知道答案了”
A : “只要在8的基础上加1就行了”
A : “所以你不用重新计算,因为你记住了第一个等式的值为8!动态规划算法也可以说是 ‘记住求过的解来节省时间’”

三、感受一下递归算法、备忘录算法、动态规划

leetcode原题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。

有些小伙伴第一次见这个题的时候,可能会有点蒙圈,不知道怎么解决。其实可以试想:

要想跳到第10级台阶,要么是先跳到第9级,然后再跳1级台阶上去;要么是先跳到第8级,然后一次迈2级台阶上去。
同理,要想跳到第9级台阶,要么是先跳到第8级,然后再跳1级台阶上去;要么是先跳到第7级,然后一次迈2级台阶上去。
要想跳到第8级台阶,要么是先跳到第7级,然后再跳1级台阶上去;要么是先跳到第6级,然后一次迈2级台阶上去。

假设跳到第n级台阶的跳数我们定义为f(n),很显然就可以得出以下公式:

f(10) = f(9)+f(8)
f (9) = f(8) + f(7)
f (8) = f(7) + f(6)

f(3) = f(2) + f(1)
即通用公式为: f(n) = f(n-1) + f(n-2)

我们现在确定一下界限

通常设为为0和1,但是0代表还没有上阶梯,所以要从1开始。再根据公式f(n) = f(n-1) + f(n-2),可以知道界限需要设为1,2,并且f(1) = 1,f(2) = 2.

递归算法

class Solution {
    public int numWays(int n) {
    if(n == 1){
        return 1;
    }
     if(n == 2){
        return 2;
    }
    return numWays(n-1) + numWays(n-2);
    }
}

去leetcode提交一下,发现有问题,超出时间限制了
在这里插入图片描述
为什么超时了呢?递归耗时在哪里呢?先画出递归树看看:
在这里插入图片描述
我们先来看看这个递归的时间复杂度吧:

递归时间复杂度 = 解决一个子问题时间*子问题个数

一个子问题时间 = f(n-1)+f(n-2),也就是一个加法的操作,所以复杂度是 O(1);
问题个数 = 递归树节点的总数,递归树的总节点 = 2n-1,所以是复杂度O(2n)。

因此,青蛙跳阶,递归解法的时间复杂度 = O(1) * O(2^n) = O(2^n),就是指数级别的,爆炸增长的,如果n比较大的话,超时很正常的了。

既然存在大量重复计算,那么我们可以先把计算好的答案存下来,即造一个备忘录,等到下次需要的话,先去备忘录查一下,如果有,就直接取就好了,备忘录没有才开始计算,那就可以省去重新重复计算的耗时啦!这就是带备忘录的解法。

带备忘录的递归解法(自定向下)

一般使用一个数组或者一个哈希map充当这个备忘录。

第一步,f(10)= f(9) + f(8),f(9) 和f(8)都需要计算出来,然后再加到备忘录中,如下:
在这里插入图片描述
第二步, f(9) = f(8)+ f(7),f(8)= f(7)+ f(6), 因为 f(8) 已经在备忘录中啦,所以可以省掉,f(7),f(6)都需要计算出来,加到备忘录中~
在这里插入图片描述
第三步, f(8) = f(7)+ f(6),发现f(8),f(7),f(6)全部都在备忘录上了,所以都可以剪掉。
在这里插入图片描述
所以呢,用了备忘录递归算法,递归树变成光秃秃的树干咯,如下:
在这里插入图片描述
带备忘录的递归算法,子问题个数=树节点数=n,解决一个子问题还是O(1),所以带备忘录的递归算法的时间复杂度是O(n)。接下来呢,我们用带备忘录的递归算法去撸代码,解决这个青蛙跳阶问题的超时问题咯~,代码如下:

public class Solution {
    //使用哈希map,充当备忘录的作用
    Map<Integer, Integer> tempMap = new HashMap();
    public int numWays(int n) {
        // n = 0 也算1种
        if (n == 0) {
            return 1;
        }
        if (n <= 2) {
            return n;
        }
        //先判断有没计算过,即看看备忘录有没有
        if (tempMap.containsKey(n)) {
            //备忘录有,即计算过,直接返回
            return tempMap.get(n);
        } else {
            // 备忘录没有,即没有计算过,执行递归计算,并且把结果保存到备忘录map中,对1000000007取余(这个是leetcode题目规定的)
            tempMap.put(n, (numWays(n - 1) + numWays(n - 2)) % 1000000007);
            return tempMap.get(n);
        }
    }
}

自底向上的动态规划

动态规划跟带备忘录的递归解法基本思想是一致的,都是减少重复计算,时间复杂度也都是差不多。但是呢:

带备忘录的递归,是从f(10)往f(1)方向延伸求解的,所以也称为自顶向下的解法。
动态规划从较小问题的解,由交叠性质,逐步决策出较大问题的解,它是从f(1)往f(10)方向,往上推求解,所以称为自底向上的解法。

动态规划有几个典型特征,最优子结构、状态转移方程、边界、重叠子问题,在青蛙跳阶问题中:

  • f(n-1)和f(n-2) 称为 f(n) 的最优子结构
  • f(n)= f(n-1)+f(n-2)就称为状态转移方程
  • f(1) = 1, f(2) = 2 就是边界啦
  • 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)就是重叠子问题。
public class Solution {
    public int numWays(int n) {
        if (n<= 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        int a = 1;
        int b = 2;
        int temp = 0;
        for (int i = 3; i <= n; i++) {
            temp = (a + b)% 1000000007;
            a = b;
            b = temp;
        }
        return temp;
    }
    }

四、动态规划的解题套路

什么样的问题可以考虑使用动态规划解决呢?

如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。

比如一些求最值的场景,如最长递增子序列、最小编辑距离、背包问题、凑零钱问题等等,都是动态规划的经典应用场景。

动态规划的解题思路:

  • 穷举分析,即做树状图找规律
  • 确定边界
  • 去欸的那个最优子结构
  • 写出状态转移方程

1. 穷举分析

当台阶数是1的时候,有一种跳法,f(1) =1
当只有2级台阶时,有两种跳法,第一种是直接跳两级,第二种是先跳一级,然后再跳一级。即f(2) = 2;
当台阶是3级时,想跳到第3级台阶,要么是先跳到第2级,然后再跳1级台阶上去,要么是先跳到第 1级,然后一次迈 2 级台阶上去。所以f(3) = f(2) + f(1) =3
当台阶是4级时,想跳到第3级台阶,要么是先跳到第3级,然后再跳1级台阶上去,要么是先跳到第 2级,然后一次迈 2 级台阶上去。所以f(4) = f(3) + f(2) =5
当台阶是5级时…

2. 确定边界

通过穷举分析,我们发现,当台阶数是1的时候或者2的时候,可以明确知道青蛙跳法。f(1) =1,f(2) = 2,当台阶n>=3时,已经呈现出规律f(3) = f(2) + f(1) =3,因此f(1) =1,f(2) = 2就是青蛙跳阶的边界。

3. 确定最优子结构

n>=3时,已经呈现出规律 f(n) = f(n-1) + f(n-2) ,因此,f(n-1)和f(n-2) 称为 f(n) 的最优子结构。什么是最优子结构?有这么一个解释:

4. 写出状态转移方程

通过前面3步,穷举分析,确定边界,最优子结构,我们就可以得出状态转移方程啦

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

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

相关文章

sql 优化

sql 优化1. mysql 基础架构1.1 mysql 的组成2. mysql 存储引擎2.1MyISAM2.2 InnoDB2.3 MyISAM 和 InnoDB 的对比3. mysql 索引3.1 Hash 索引3.2 B-Tree 索引3.3 BTree 索引3.4 R-Tree 索引3.5 Full-Text 索引4. sql 优化4.1 避免 select *4.2 避免在where子句中使用or来连接条件…

PTA L1-046 整除光棍(详解)

前言&#xff1a;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 这里所谓的“光棍”&#xff0c;并不是指单身汪啦~ 说的是全部由1组成的数字&#xff0c;比如1、11、111、1111等。传说任何一个光棍都能被…

【数据库】sql函数和多表关联查询

目录 一&#xff0c;SQL函数 1&#xff0c;聚合函数 1&#xff0c; count函数 2&#xff0c; AVG函数 3&#xff0c; SUM函数 4&#xff0c; MAX函数 5&#xff0c; MIN函数 6&#xff0c;数据分组——GROUP BY 7&#xff0c;限定组的结果&#xff0c;HAVING 8&#x…

在线支付系列【23】支付宝开放平台产品介绍

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录前言支付产品App 支付手机网站支付电脑网站支付新当面资金授权当面付营销产品营销活动送红包会员产品App 支付宝登录人脸认证信用产品芝麻 GO芝麻先享芝麻免押芝麻工作证安全产品交易安全防护其…

Centos7上Docker安装

文章目录1.Docker常识2.安装Docker1.卸载旧版本Docker2.安装Docker3.启动Docker4.配置镜像加速前天开学啦~所以可以回来继续卷了哈哈哈&#xff0c;放假在家效率不高&#xff0c;在学校事情也少点(^_−)☆昨天和今天学了学Docker相关的知识&#xff0c;也算是简单了解了下&…

设计模式C++实现12:抽象工厂模式

参考大话设计模式&#xff1b; 详细内容参见大话设计模式一书第十五章&#xff0c;该书使用C#实现&#xff0c;本实验通过C语言实现。 抽象工厂模式&#xff08;Abstract Factory&#xff09;&#xff0c;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们…

Python之字符串精讲(下)

前言 今天继续讲解字符串下半部分&#xff0c;内容包括字符串的检索、大小写转换、去除字符串中空格和特殊字符。 一、检索字符串 在Python中&#xff0c;字符串对象提供了很多用于字符串查找的方法&#xff0c;主要给大家介绍以下几种方法。 1. count() 方法 count() 方法…

CHAPTER 5 Jenkins SonarQube

Jenkins & SonarQube5.1 安装SonarQube1. 下载镜像2. 导出到其他服务器3. 准备工作4. docker-compose文件5. 启动容器5.2 登录SonarQube1.登录2. 安装中文语言插件3. 安装其他插件5.3 部署扫描器sonar-scanner1. 部署sonar-scanner2. 新建项目3. 扫描代码4. 查看报告5.4 Je…

Prometheus 的介绍和安装

介绍 Prometheus 是一个开源的监控和报警系统,最初由SoundCloud于2012年创建,随着越来越多的公司采用Prometheus以及非常活跃的社区,Prometheus于2016年加入云原生基金会,成为Kubernetes之后的第二个托管项目,并于2018年毕业。 特点 通过PromQL来对基于指标名称和键值对…

独立产品灵感周刊 DecoHack #047 - 安卓手机上最有用的APP

本周刊记录有趣好玩的独立产品设计开发相关内容&#xff0c;每周发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以点击订阅我的周刊。为保证每期都能收到&#xff0c;建议邮件订阅。欢迎通过 Twitter 私信推荐或投稿。&#x1f4bb; 产品推荐 1. Bouncer Tempor…

算法训练营 day45 动态规划 0-1背包理论 分割等和子集

算法训练营 day45 动态规划 0-1背包理论 分割等和子集 0-1背包理论 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 在下面的讲解中&…

python 使用 thrift 教程

一、前言&#xff1a;   Thrift 是一种接口描述语言和二进制通信协议。以前也没接触过&#xff0c;最近有个项目需要建立自动化测试&#xff0c;这个项目之间的微服务都是通过 Thrift 进行通信的&#xff0c;然后写自动化脚本之前研究了一下。 需要定义一个xxx.thrift的文件&…

【C++】十分钟带你入门C++

目录零 内容概括一 C关键字二 命名空间2.1 命名空间定义2.2 命名空间的使用三 C输入和输出四 缺省参数4.1 缺省参数的概念4.2 缺省参数分类五 函数重载5.1 函数重载的概念六 引用6.1 引用概念6.2 引用特性6.3 常引用6.4 使用场景6.5 效率比较6.6 引用和指针的区别七 内联函数7.…

最简易的教程 -一篇文章教会你 用Python打包文件

前言 嗨嗨&#xff0c;好久不见&#xff0c;我是 我叫 … emmm你们好 我是一堆英文字母&#xff08;名字乱打的不好yi shi ~&#xff09; 看到文章的人多不多&#xff0c;我不知道 &#xff0c;招呼我还是要打一个的 &#x1f44d; 今天文章很简单&#xff0c;打包改图标 用…

C++关键字之const、inline、static

C 关键字总结 1.const const是 constant 的缩写&#xff0c;本意是不变的、不易改变的意思。在C中用来修饰内置类型变量&#xff0c;自定义对象&#xff0c;成员函数&#xff0c;返回值&#xff0c;函数参数使用如下&#xff1a; //修饰普通类型变量 const int a 7; int ba;…

人工智能对教育的冲击有多大?

人工智能对教育有巨大冲击 高考改革也会发生重大变化 教育系统其实是一个坚固的堡垒 再坚固也要适应未来 趣讲大白话&#xff1a;让我未来更有竞争力 *********** 创造和创新的意识和能力 复杂性和不确定性的适应能力 应该是改革的方向 【安志强趣讲信息科技】74期 掌握信息科…

【人工智能】对贝叶斯网络进行吉布斯采样

问题 现要求通过吉布斯采样方法&#xff0c;利用该网络进行概率推理&#xff08;计算 P(RT|SF, WT)、P2(CF|WT)的概率值&#xff09;。 原理 吉布斯采样的核心思想为一维一维地进行采样&#xff0c;采某一个维度的时候固定其他的维度&#xff0c;在本次实验中&#xff0c;假…

分享开放通达信l2接口的过程,开发之后怎么使用?

随着互联网的不断进步&#xff0c;信息技术的不断发展&#xff0c;通达信l2接口技术逐步成熟。那么&#xff0c;这些开放通达信l2接口开发的过程是怎么样的呢?期间又会遇到什么问题&#xff0c;开放之后又会怎么使用呢&#xff1f;这篇文章带你深入了解。 通达信l2接口不像一…

高通8155 GPS HAL层代码移植

1.添加gps hal层代码包 将ublox gps芯片的hal层代码拷贝至apps/LINUX/android/hardware/ublox/路径下&#xff0c;树状图如下&#xff1a; 2.修改编译选项 将新增的ublox gps hal层代码编译进入image&#xff0c;需要修改apps/LINUX/android/device/qcom/msmnile_gvmgh/路径下的…

基于Python来爬取某音动态壁纸,桌面更香了!

至于小伙伴们想要这个封图&#xff0c;我也没有。不过继续带来一波靓丽壁纸&#xff0c;而且是动态的&#xff0c;我的桌面壁纸又换了&#xff1a;每天换着花样欣赏一波波动态壁纸桌面立刻拥有了高颜值&#xff0c;简直跟刷美女短视频一样啊。对的&#xff0c;这些动态壁纸就是…