动态规划快速入门

2023-11-06

更多内容,欢迎关注微信公众号:全菜工程师小辉。公众号回复关键词,领取免费学习资料。

动态规划算法一直是面试手撕算法中比较有挑战的一种类型。很多的分配问题或者调度问题实际上都可能用动态规划进行解决。(当然,如果问题的规模较大,有时候会抽象模型使用动归来解决,有时候则可以通过不断迭代的概率算法解决查找次优解)

所以,动归很重要,至少算法思想很重要。

什么是动态规划?

通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 > 最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。

> 重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。

不理解不用怕,结合后面题目来理解这些概念。这些概念完全是已经会动归的人来总结出来的,所以先理解动归,然后再来看这些文绉绉的概括。

分治与动态规划

共同点:
二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决)的子问题。然后将子问题的解合并,形成原问题的解。

不同点:

  • 分治法将分解后的子问题看成相互独立的,通过用递归来做。
  • 动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。

动态规划的步骤

问题建模

  1. 根据问题,找到【最优子结构】。把原问题从大化小的第一步,找到比当前问题要小一号的最好的结果,而一般情况下当前问题可以由最优子结构进行表示。
  2. 确定问题的【边界】。根据上述的最优子结构,一步一步从大化小,最终可以得到最小的,可以一眼看出答案的最优子结构,也就是边界。
  3. 通过上述两步,通过分析最优子结构与最终问题之间的关系,我们可以得到【状态转移方程】。

问题求解的各个方法

暴力枚举:

所有的动态规划问题都可以通过多层嵌套循环遍历所有的可能,将符合条件的个数统计起来。只是时间复杂度是指数级的,所以不推荐。

递归:

  1. 递归的时间复杂度是由递归层数和最优子结构的个数决定的。
  2. 在爬阶梯问题,最少找零钱问题中,递归的时间复杂度和空间复杂度都比动归方法的差,但是在国王与金矿的问题中,不同的数据规模,动归方法的时间复杂度和空间复杂度不一定比递归的要好。所以具体问题具体分析。

> 上面提到的三个问题是动态规划里很常见的题目,题目内容可以百度查看一下。篇幅原因,本文后边只讲解前两道题

备忘录算法:

  1. 在阶梯数N比较多的时候,递归算法的缺点就显露出来了:时间复杂度很高。如果画出递归图(像二叉树一样),会发现有很多很多重复的节点。然而传统的递归算法并不能识别节点是不是重复的,只要不到终止条件,它就会一直递归下去。
  2. 为了避免上述情况,使递归算法能够不重复递归,就把已经得到的节点都存起来,下次再遇到的时候,直接用存起来的结果就行了。这就是备忘录算法。
  3. 备忘录算法的时间复杂度和空间复杂度都得到了简化。

动态规划算法:

  1. 上述的备忘录算法,尽管已经不错了,但是依然还是从原问题,遍历得到所有的最小子问题,空间复杂度是O(N)。
  2. 为了再次缩小空间复杂度,我们可以自底向上的构造递归问题,通过分析最优子结构与最终问题之间的关系,我们可以得到【状态转移方程】。 然后从最小的问题不断往上迭代,即使一直迭代到最大的原问题,也是只依赖于前面的几个最优子结构。这样,空间复杂度就大大简化。也就得到了动归算法算法。

例题

例1: Climbing Stairs(爬楼梯问题)
leetcode原题:你正在爬一个有n个台阶的楼梯,每次只能上1个或者2个台阶,那么到达顶端共有多少种不同的方法?

  1. 建立模型:
  • 最终问题F(N):假设从0到达第N个台阶的方法共有F(N)个。
  • 最优子结构F(N-1),F(N-2):到达N个台阶,有两种可能,第一种可能是从第 N-1 个台阶上1个台阶到达终点,第二种可能是从第 N-2 个台阶上2个台阶到达终点。
  • 最优子结构与最终问题之间的关系:按照上述表达,那么可以归纳出F(N) = F(N-1) + F(N-2) (n>=3)
  • 边界:F(1) = 1,F(2) = 2
  1. 问题求解:
  • 递归:
class Solution {
    int climbStairs(int n) {
        if (n <= 2) {
            return n;
        } else {
            return climbStairs(n - 1) + climbStairs(n - 2);
        }
    }
}

> 递归的时间复杂度是由递归层数和最优子结构的个数决定的。这里的阶梯数是 N ,最优子结构个数是2。如果想象成一个二叉树,那么就可以认为是一个高度为N-1,节点个数接近2的N-1次方的树,因此此方法的时间复杂度可以近似的看作是O(2<sup>N</sup>) 。

  • 备忘录算法:
    这里我们想到了把重复的参数存储起来,下次递归遇到时就直接返回该参数的结果,也就是备忘录算法了,最简单的备忘录就是哈希表。
class Solution {
    private Map<integer, integer> map = new HashMap&lt;&gt;();

    int climbStairs(int n) {
        if (n &lt;= 2) {
            return n;
        } else if (map.containsKey(n)) {
            return map.get(n);
        } else {
            int value = climbStairs(n - 1) + climbStairs(n - 2);
            map.put(n, value);
            return value;
        }
    }
}
  • 动态规划:
    之前都是自顶向下的求解,考虑一下自底向上的求解过程。从F(1)和F(2)边界条件求,可知F(3) = F(1)+F(2)。不断向上,可知F(N)只依赖于前两个状态F(N-1)和F(N-2)。于是我们只需要保留前两个状态,就可以求得F(N)。相比于备忘录算法,我们再一次简化了空间复杂度。
class Solution {
    int climbStairs(int n) {
        if (n &lt;= 2) {
            return n;
        }
        // 边界条件
        int a = 1;
        int b = 2;
        int result = 0;
        // 最优子结构与最终问题之间的关系
        for (int i = 3; i &lt;= n; i++) {
            result = a + b;
            a = b;
            b = result;
        }
        return result;
    }
}

> 空间复杂度O(1), 时间复杂度O(N)

例2: Making change using the fewest coins(最少找零钱问题)
Google面试题:假设你是一家自动售货机制造商的程序员。你的公司正设法在每一笔交易 找零时都能提供最少数目的硬币以便工作能更加简单。已知硬币有四种(1美分,5美分,10美分,25美分)。假设一个顾客投了1美元来购买37美分的物品 ,你用来找零的硬币的最小数量是多少?

  1. 建立模型:
  • 最优子结构:回想找到最优子结构的方法,就是往后退一步,能够得到的最好的结果。这里有四个选择,1 + mincoins(63-1),1 + mincoins(63-5),1 + mincoins(63-10) 或者 1 + mincoins(63-25),这四个选择可以认为是63的最优子结构。
  • 状态转移方程:按照上述的最优子结构,mincoins(63)也就等于上述四个最优子结构的最小值。
  • 边界: 当需要找零的面额正好等于手中单枚硬币的金额时,返回1即可。
  1. 问题求解:
  • 递归:
class Solution {
    Set<integer> coinSet = new HashSet<integer>() {
        {
            add(1);
            add(5);
            add(10);
            add(25);
        }
    };

    int getFewestCoins(int n) {
        if (n &lt; 1) {
            return 0;
        }
        if (coinSet.contains(n)) {
            return 1;
        }
        int minCoins = n;
        int numCoins = Integer.MAX_VALUE;

        for (int coin : coinSet) {
            if (n &gt;= coin) {
                // 如果要计算的n小于单个硬币金额,则不能出现在状态转移方程中
                numCoins = 1 + getFewestCoins(n - coin);
            }
            // 更新最小值
            if (numCoins &lt; minCoins) {
                minCoins = numCoins;
            }
        }
        return minCoins;
    }
}
  • 备忘录算法:
    就是将递归里计算的中间变量都保存在一个哈希表,代码略。

  • 动态规划:
    自底向上,从找零数等于1开始往上迭代,参考最优子结构,记录下来最少硬币数。一直迭代到实际要求。

class Solution {
    Set<integer> coinSet = new HashSet<integer>() {
        {
            add(1);
            add(5);
            add(10);
            add(25);
        }
    };

    int getFewestCoins(int n) {
        int[] list = new int[n + 1];
        List<integer> subCal = new ArrayList&lt;&gt;();
        for (int i = 0; i &lt;= n; i++) {
            // 边界
            if (i &lt;= 1) {
                list[i] = i;
                continue;
            }
            for (int cent : coinSet) {
                if (i &gt;= cent) {
                    subCal.add(list[i - cent] + 1);
                }
            }
            list[i] = Collections.min(subCal);
            subCal.clear();
        }
        return list[n];
    }
}

更多内容,欢迎关注微信公众号:全菜工程师小辉。公众号回复关键词,领取免费学习资料。

哎呀,如果我的名片丢了。微信搜索“全菜工程师小辉”,依然可以找到我

</integer></integer></integer></integer></integer></integer,>

转载于:https://my.oschina.net/u/2425469/blog/3099585

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态规划快速入门 的相关文章

  • 会议OA项目之会议发布(多功能下拉框的详解)

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于OA项目的相关操作吧 目录 Welcome Huihui s Code World 一 主要功能点介绍 二 效果展示 三 前端代码 jsp js 四 后端代码
  • DNS解析与CDN加速

    DNS解析与CDN加速 一 DNS解析 1 域名系统DNS 2 DNS解析 二 CDN加速 1 什么是CDN 2 静态加速 3 动态加速 一 DNS解析 1 域名系统DNS 域名系统的前世今生 域名系统的产生的原因是用户通过形如198 26
  • Web自动化测试流程:从入门到精通,帮你成为测试专家!

    摘要 Web应用程序在今天的软件开发中占据着越来越重要的地位 保证Web应用程序的质量和稳定性是非常必要的 而自动化测试是一种有效的方法 本文将介绍Web自动化测试流程 并提供代码示例 步骤一 选取测试工具 选择适合自己团队的自动化测试工具
  • Linux下安装Mysql5.7,超详细完整教程,以及云mysql连接

    安装前环境检查 1 首先检查自己电脑有没有安装过mysql 输入如下 rpm qa grep mysql 如果有则清理干净在安装 输入 whereis mysql 找到文件夹目录 再把它删除 rpm e nodeps mysql xxxx
  • 华为手机微信与电脑连接到服务器失败怎么办,华为微信到电脑上找不到了怎么办...

    1 华为手机连接电脑后找不到微信保存的视频 应该是在微信专用的文件夹里 文件夹的名字是英文的腾信 如果视频不多可以登陆电脑版微信 然后用文件助手传到电脑再保存 2 华为荣耀10微信存储图片连接电脑找不到 查找微信保存图片的文件信息 打开 文
  • React组件化一

    29 9React课程 第02节 react组件化 第2节 02课react组件化 02课react组件化 02课react组件化 初始化显示constructor构造函数 要使用super 否则没法在内部使用this 2与3之间要对组件进
  • Centos7本地yum安装FTP和HTTP服务

    Centos镜像包下载 http mirror centos org altarch 7 isos 32位 i386 64位 带64的 1 将Vmware中的光驱设置为镜像包 在虚拟机关闭时设置 1 打开虚拟机设置 2 选择CD DVD 3
  • clang简介

    文章目录 clang编译器 clang选项 阶段选择选项 语言选择和模式选项 目标选择选项 代码生成选项 O0 O1 O2 O3 Ofast Os Oz Og O O4 g gline tables only gmodules fstand
  • 适用于 24 V 电源系统的车载网络 ESD 保护

    Nexperia 安世半导体 近日推出符合 AEC Q101 标准的产品组合 其中包含六个 ESD 保护器件 PESD2CANFD36XX Q 旨在保护 LIN CAN CAN FD FlexRay 和SENT 等车载网络 IVN 中的总线
  • 日期补0位

    function getNowFormatDate var day new Date var Year 0 var Month 0 var Day 0 var CurrentDate 初始化时间 Year day getYear 有火狐下2
  • Red Hat Enterprise Linux 8 配置yum源

    Red Hat Enterprise Linux 8 配置YUM源的两种方式 一 本地YUM源 1 备份源文件 cd etc yum repos d mkdir bak mv repo bak 2 挂载镜像 mount t iso9660
  • 面试官都在问

    面试官都在问 Linux命令mpstat详解 1 mpstat的基本用法 mpstat的全称为Multiprocessor Statistics 是一款常用的多核CPU性能分析工具 用来实时查询每个CPU的性能指标 以及所有CPU的平均指标
  • 用qsetting实现文件保存和读取

    QSettings 是 Qt 库中的一个类 可以用来读取和保存应用程序的配置数据 使用 QSettings 可以方便地保存和读取配置信息 比如窗口的大小和位置 最近打开的文件列表等 实现保存文件的步骤如下 创建 QSettings 对象 并
  • OpenCV 3.3.1及Contrib附加库安装教程及问题Undefined reference to cv::xfeatures2d

    INSTALL OPENCV ON UBUNTU OR DEBIAN 1 KEEP UBUNTU OR DEBIAN UP TO DATE sudo apt get y update sudo apt get y upgrade sudo
  • cpp课程设计实验题:编写程序,定义抽象基类Shape(形状),由它派生出3个派生类: Circle(圆形)、Rectangle(矩形)和Square 正方形),用函数函数ShowArea()分别显

    编写程序 定义抽象基类Shape 形状 由它派生出3个派生类 Circle 圆形 Rectangle 矩形 和Square 正方形 用函数函数ShowArea 分别显示各种图形的面积 最后还要显示所有图形的总面积 要求用基类指针数组 使它的
  • adb 指令

    1 基本指令 指令 adb version 显示 adb 版本 指令 adb help 帮助信息 查看 adb 所支持的所有命令 指令 adb start server 启动 adb 服务 指令 adb kill server 关闭 adb
  • Unity 分帧加载和分块加载

    分帧加载和分块加载 在我们实际做项目的时候 往往会遇见需要创建大量数据的时候 这时如果在一帧里面大量创建数据 那我们的游戏就会发生卡顿从而降低了用户的体验 为了解决这种情况 可以使用使用分帧加载使得每帧只加载固定数量的数据来解决 也可以使用
  • 经纬度坐标与距离的相互转换及其实现

    经纬度坐标与距离的相互转换 1 经纬度与距离角度的换算关系 2 Python代码实现 1 经纬度与距离角度的换算关系 a 在纬度相等的情况下 经度每隔0 00001度 距离相差约1米 每隔0 0001度 距离相差约10米 每隔0 001度
  • 【ElementUI组件优化】自定义icon图标的使用

    风雨里做个大人 阳光下做个小孩 前端经常会用到UI提供的各种图表 推荐阿里的图标库 如果UI要求不是很严格 我们可以自己在图标库中找到想要的图标 搜索之后可以点击下载 在ElementUI中使用Icon图标组件使用非常简单 同时 在图标按钮
  • 微信小程序如何实现(点击发送弹幕)

    扫一扫以上小程序 许愿灯池 可以查看具体点击发送弹幕功能 效果图 点击 祝福一下吧 即可弹出弹幕 直接上代码 index wxml

随机推荐

  • spark学习7:RDD编程

    1 目录 2 创建RDD 两种方式 2 1从文件系统加载 sc textFile 方法来加载文件数据 并将文件数据转换为RDD 2 1 1 从本地文件加载数据 val rdd1 sc textFile file home hzp Docum
  • error:LNK2005 函数已经在*.obj中定义

    出现上面的错误 只要原因有如下几个 1 头文件的重复包含 包含的头文件中含有变量 函数 类的定义 在其他使用的地方多次包含 造成重复包含 产生LNK2005错误 有两种解决方法 1 使用宏 在头文件head h中加入 ifndef HEAD
  • IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

    1 前言 在IM这种讲究高并发 高消息吞吐的互联网场景下 MQ消息中间件是个很重要的基础设施 它在IM系统的服务端架构中担当消息中转 消息削峰 消息交换异步化等等角色 当然MQ消息中间件的作用远不止于此 它的价值不仅仅存在于技术上 更重要的
  • 华北电力大学计算机专业学什么,华北电力大学计算机专业与杭州电子科技大学计算机专业哪一个强...

    技校网专门为您推荐的类似问题答案 问题1 北京工业大学 华北电力大学 北京 西安电子科技大学这三个学校的信息安全专业哪个比较 不要相信一个新设置的专业 我就上华电一个新兴专业 就业这个费劲啊 华电还是电力为主 弱电方面就业不是很好 推荐西电
  • 定时执行shell脚本,让其停掉 在重启

    bin bash appname zhihu data 0 0 1 SNAPSHOT jar binPath u01 isi zhihu data monitor ps ef grep appname grep v grep wc l if
  • 【猴博士】概率论与数理统计 笔记总结(完结)

    前言 视频在B站看 视频在MOOC看 是笔记 可能不全 其他没写的章节是因为我考试不考 就没看了 概率论 第一章 随机事件和概率 概率论与数理统计 猴博士 笔记 p1 p2 古典概型 几何概型 概率论与数理统计 猴博士 笔记 p3 4 事件
  • 51单片机实验1-流水灯的设计(流水灯,蜂鸣器,爆闪灯)

    关于软件的使用我们用的是proteus和keil软件 关于软件的安装和使用 这里就不在说明了 如果软件还没有安装可以参考 proteus安装 Proteus软件的安装与使用方法 超详细 http t csdn cn ZaUjM keil安装
  • 电阻上下拉是最常见的用法,那你是不是真的吃透了它?给小白讲讲上拉电阻和下拉电阻!----------------源自玩转单片机与嵌入式

    上拉和下拉电阻主要用于正确偏置数字电路门电路的输入 以防止它们在没有输入条件时的状态是随机浮动的 数字逻辑门可用于连接外部电路或设备 但必须注意确保其输入或输出正常工作并提供预期的开关条件 一 为什么要用上下拉电阻 现代数字逻辑门 IC 和
  • 应届日记之TreeUtiles工具类的使用

    今天遇到一个问题 需要将数据库里面的省市查出来 返回给前端树形结构 用到了TreeUtiles工具类 将list组装成一棵树返回 param list param primaryfieldName param parentFieldName
  • C++ New对象和直接声明对象的区别

    1 new出来的对象需要使用指针接收 而直接声明的不用 例如 A a new A 与A a 2 new出来的对象是直接使用堆空间 而局部声明一个对象是放在栈中 3 new出来的对象类似于申请空间 因此需要delete销毁 而直接声明的对象则
  • 动态路由权限,按钮的权限,菜单权限分别是怎么实现的

    首先什么是前端权限控制 就是当用户登录之后 根据不用用户拥有的权限动态添加 addRoutes 用户能访问的路由页面和能看到的菜单页面 v for 动态路由权限 1 本质就是利用addRoutes这个api来实现动态添加路由权限 然后还可以
  • robotstudio喷涂组件paintapplicator没有显色效果

    因为part这里只能选择仿真之前已经存在的部件 若是像仿真后用source组件生成的新物体 就选择不了 即使你使用传感器 让传感器将检测到的物体传给part 也一样没有喷涂的颜色效果 如果一定要实现 可以参照这个视频 https www b
  • 我的机器学习--线性回归

    1 最小二乘法 上述方法可以直接得到线性回归方程 import numpy as np import matplotlib pyplot as plt x 2 np random rand 100 1 y 4 3 x np random r
  • C语言指针转换为intptr_t类型

    随笔 155 文章 2 评论 342 C语言指针转换为intptr t类型 1 前言 今天在看代码时 发现将之一个指针赋值给一个intptr t类型的变量 由于之前没有见过intptr t这样数据类型 凭感觉认为intptr t是int类型
  • 一个五位数判断他是否为回文数。

    一个五位数判断他是否是回文数 代码 num int input munber n flag True while True if 10000 lt num lt 100000 print input number num break els
  • 腾讯三面被问到有没有参加过CTF?我反手就是一套军体拳打得面试官哑口无言!

    目录 前言 正文 什么是CTF 什么是PWN 为什么要学CTF CTF竞赛模式 CTF各大题型简介 学之前的思考 分析赛题情况 常规做法 CTF比赛需要的知识储备 CTF比赛的神器 恶补基础知识 信息安全专业知识推荐图书 前言 这是一场紧张
  • Typora字体颜色修改

    Typora字体颜色修改 typora中不能直接修改字体颜色 但有三种方法可以实现修改Typora中颜色 第一种 安装AutoHotKey 较简单 安装AutoHotKey windows系统快捷键设置软件 从而通过设置快捷键来达到修改字体
  • macbook brew install 经常遇见 No such file or directory @ rb_sysopen

    安装php brew install php 在执行过程中经常报错 比如以下 gt Installing php dependency openldap gt Pouring openldap 2 5 8 arm64 monterey bo
  • Docker介绍

    目录 docker定义 docker解决了什么问题 docker技术边界 docker给我们带来了哪些改变 docker和虚拟机的区别 docker基本架构 基本架构图 RootFs Linux Namespace 进程命名空间 查看元祖进
  • 动态规划快速入门

    更多内容 欢迎关注微信公众号 全菜工程师小辉 公众号回复关键词 领取免费学习资料 动态规划算法一直是面试手撕算法中比较有挑战的一种类型 很多的分配问题或者调度问题实际上都可能用动态规划进行解决 当然 如果问题的规模较大 有时候会抽象模型使用