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

【数据结构和算法】三、动态规划原理讲解与实战演练

目录

1、什么是动态规划?

2、动态规划实战演练

2.1 力扣题之爬楼梯问题

(1)解题思路1:

(2)解题思路2:

(3)动态规划(DP):解题思路

(4)动态规划理论

2.2 力扣题之海盗船长

(1)解题思路1:

(2)解题思路2:

(3)动态规划:解题思路3:


1、什么是动态规划?

        动态规划(Dynamic Programming,DP)是把复杂问题分解为简单的子问题的求解方法。

        动态规划的基本思想虽然简单,但分解的子问题很多都不一样。所以需要多做一些练习,接触并了解各种子问题及分解的思路,结合着不同数据结构,才能逐渐掌握DP的技巧。

        所以,DP归纳起来就是多做练习,多思考,逐渐摸索题目的思考逻辑和优化思路。才能掌握使用DP解题的技巧。


   从实际问题出发,分几步走,不断练习、迭代熟练:

  1. 暴力求解(枚举)
  2. 拆分子问题(DP)解法
  3. DP原理与题型相结合的分析

2、动态规划实战演练

2.1 力扣题之爬楼梯问题

以力扣著名的题“爬楼梯”为例子:

  • 爬楼梯问题: . - 力扣(LeetCode)

    假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

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

    示例 1:

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

    示例 2:

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

    提示:

    • 1 <= n <= 45

    (1)解题思路1:

    暴力求解,排列所有1,2的组合。

    寻找总和为n的,不同数字长度的组合。

    from itertools import productdef climbStairs(n):pms = []for rep in range(1,n+1):permutations = list(product([1,2],repeat=rep))for pm in permutations:if sum(pm) == n:pms.append(pm)return len(pms)
    

    ※ itertools是python为高效循环而创建迭代器的函数库 。product就是一个笛卡尔积(嵌套for循环)功能实现的函数。

    • 时间复杂度O(n^3)
    • 空间复杂度O(n)

    (2)解题思路2:

    问题寻找的是爬楼梯的方法数量,而不是具体统计每次走几阶。

    所以问题关注的是每次爬1阶、爬2阶两种走法的组合上。

    假设n=3,可以直接排列一下相应的组合

    3 = 1 + 1 + 1
    3 = 2 + 1
    3 = 1 + 2
    

    简单直观,但我们要寻找的爬楼梯的规律。似乎还没有发现,继续增加n的数量~

    当n=4:

    4 = 1 + 1 + 1 + 1
    4 = 2 + 1 + 1
    4 = 1 + 2 + 14 = 1 + 1 + 2
    4 = 2 + 2
    

    当n=5时:

    5 = 1 + 1 + 1 + 1 + 1
    5 = 2 + 1 + 1 + 1
    5 = 1 + 2 + 1 + 15 = 1 + 1 + 2 + 1
    5 = 2 + 2 + 15 = 1 + 1 + 1 + 2
    5 = 2 + 1 + 2
    5 = 1 + 2 + 2
    

            排列组合的方式,让我们似乎观察到了数值的规律。那就是n阶的走法,包含了n-1阶和n-2阶的走法。且 n阶的走法 = (n-1)阶走法 + (n-2)阶走法

    简单的循环遍历就可以完成走法的累加:

    n = 5
    n1,n2 = 1,2  # n=1和n=2情况下的走法
    res = 0
    for i in range(3, n+1):  # 从n=3时开始,直到nres = n1 + n2n1 = n2n2 = res
    print(res)
    

    测试下n=6,结果(n-1) + (n-2) = 8 + 5 = 13

    还可以转换为递归写法

    def climbStairs(n):if n <= 1:return 1return climbStairs(n-1) + climbStairs(n-2) 
    

    至此,就是暴力算法的解题思路,所有可能的组合都做一遍。

    (3)动态规划(DP):解题思路

    依据上面算法特征分析的基础上,使用一个数组动态存储n的计算结果。

    初始化数组,预先存入n-1和n-2的结果

    def climbStairs(n):if n <= 1:return ndp = [i for i in range(n+1)]for i in range(3,n+1):dp[i] = dp[i-1] + dp[i-2]return dp[-1]
    

    上面代码中的dp就是我们提到的数组,其中dp[i] = dp[i-1] + dp[i-2]

    循环执行完成后,数组中最后一次计算的结果就是爬n阶楼梯的方法数。

    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

    对于空间复杂度,还可以进一步优化。由于我们只考虑n以及n-1、n-2的值。所以,中间的过程值可以丢弃。定义一个固定长度的数组,每次计算结果动态覆盖,如下:

    def climbStairs(n):if n <= 1:return ndp = [0,1,2]for i in range(3,n+1):sum = dp[1] + dp[2]dp[1] = dp[2]dp[2] = sumreturn dp[2]
    
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    (4)动态规划理论

            学习动态规划算法,是从多种题解的思路中学习和发现。众多技术高手都给出了思路和技巧,但从实际出发,建议还是先埋头做题,积累了练习和分析思考后,再进行看高手的总结和归纳才会有“英雄所见略同”的共识。

    在这之前,针对每道题目的分析,希望能思考如下的几个问题:

    • 题目计算的目标是什么

      走台阶问题的目标是求走法组合总数

    • 计算分解的子问题是什么

      (n-1)阶走法 、(n-2)阶走法就是n阶走法的子问题 ****

    • 转移方程是否是子问题的组合

      转移方程上面已经写出来了 f(n) = f(n-1)+f(n-2) 。

    • 能否优化

      使用动态数组或字典来存储中间结果,可以有效的减少重复计算的复杂度。

      当然,涉及到使用数组等容器来实现计算和优化时,还会接触到背包问题。

2.2 力扣题之海盗船长

问题:海盗船长:. - 力扣(LeetCode)

海盗船长:船长从坐标为(0,0)的位置出发,每次只能向x轴,y轴正方向走一步,求走到x,y点有几种走法?

示例 1:

输入:m = 3, n = 7
输出:28

示例 2:

输入:n = 3, n = 2
输出:3
解释:从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

示例 3:

输入:m = 7, n = 3
输出:28

示例 4:

输入:m = 3, n = 3
输出:6

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 10^9

(1)解题思路1:

从[0,0]到[x,y],是一个从矩阵左上角向右、向下探索的过程。

想要到达[x,y]位置,必然经过[x-1,y]或者[x,y-1]

所以,路径问题的分解就是求[x , y] = [x-1,y] + [x,y-1]

设 m,n = 3,7 暴力解法

results = {}def path_count(x, y):# results = {}if x == 1 or y == 1:results[(x,y)] = 1return 1results[(x,y)] = path_count(x-1,y) + path_count(x,y-1)return results[(x,y)]print(path_count(3,7))

时间复杂度:O(mn)

空间复杂度:O(n)

(2)解题思路2:

观察上面的方案,可以发现分解的路径实际上存在着大量重复的计算

print(results)

我们可以思考:走到results中(m,n)位置的上一步,一定是(m-1,n),(m,n-1),(m-1,n-1)的位置。

这其中(m-1,n-1)走过的路径中,就包含了(m-1,n)和(m,n-1)走过的路径。

以此类推,所有(m-2,n-2)的路径中,也就包含了(m-1,n-1), (m-1,n), (m,n-1) …… 如此嵌套。我们把计算结果存储在results里面,再次遇到相同的计算时,就直接把结果提取出来。

def path_count(x, y):if x == 1 or y == 1:results[(x,y)] = 1return 1# 查找重复节点,直接返回计算后结果if (x,y) in results:return results[(x,y)]results[(x,y)] = path_count(x-1,y) + path_count(x,y-1)return results[(x,y)]

(3)动态规划:解题思路3:

动态规划方式实现:

转移方程:f(x,y) = f(x-1,y) + f(x, y-1)

分两步实现:

  1. 计算“到达”每个位置所需要的步数(初始为1)

    m,n = 3,7
    path_counts = [[1] * n for j in range(m)]
    for i in range(m):for j in range(n):print(path_counts[i][j], end=' ')print()
    
  2. 计算从起始位置,到达当前位置,步数的累加和

    for x in range(1,m):for y in range(1,n):path_counts[x][y] = path_counts[x-1][y] + path_counts[x][y-1]print(path_counts[m-1][n-1])
    

完整代码:

def path_count(x, y):path_counts = [[1] * y for j in range(x)]for i in range(1,x):for j in range(1,y):path_counts[i][j] = path_counts[i-1][j] + path_counts[i][j-1]return path_counts[x-1][y-1]

相关文章:

【数据结构和算法】三、动态规划原理讲解与实战演练

目录 1、什么是动态规划&#xff1f; 2、动态规划实战演练 2.1 力扣题之爬楼梯问题 &#xff08;1&#xff09;解题思路1: &#xff08;2&#xff09;解题思路2: &#xff08;3&#xff09;动态规划&#xff08;DP&#xff09;&#xff1a;解题思路 &#xff08;4&#x…...

交叉编译 perl-5.40.0(riscv64)

交叉编译 perl-5.40.0&#xff08;riscv64&#xff09; https://arsv.github.io/perl-cross/usage.html https://github.com/arsv/perl-cross 借助 perl-cross 进行交叉编译 https://www.perl.org/get.html#unix_like 这里获取 perl-5.40.0 的源码 https://github.com/arsv/pe…...

Leetcode 搜索旋转排序数组

这段代码是用于解决LeetCode第33题“搜索旋转排序数组”的Java解法。以下是对该算法思想的中文解释&#xff1a; 算法思想 二分查找的基本思路&#xff1a; 由于数组是部分有序的&#xff08;被旋转过&#xff09;&#xff0c;我们可以利用二分查找的思想&#xff0c;逐步缩小…...

Spring Task—定时任务

Spring Task 是 Spring 提供的一种轻量级定时任务调度功能&#xff0c;内置在 Spring 框架中。与 Quartz 等重量级调度框架相比&#xff0c;Spring Task 使用简便&#xff0c;无需额外依赖&#xff0c;适合在简单的调度任务场景中使用。通过注解配置方式&#xff0c;开发者可以…...

Spring Boot 应用开发概述

目录 Spring Boot 应用开发概述 Spring Boot 的核心特性 Spring Boot 的开发模式 Spring Boot 在企业应用开发中的优势 结论 Spring Boot 应用开发概述 Spring Boot 是由 Pivotal 团队开发的一个框架&#xff0c;基于 Spring 框架&#xff0c;旨在简化和加速基于 Spring …...

Chrome谷歌浏览器加载ActiveX控件之allWebDesktop控件介绍

背景 allWebDesktop控件是一款方便用户在线打开各类文档的OA办公控件。它设计比较轻巧&#xff0c;充分利用计算机程序资源打开文档&#xff0c;并将程序窗口嵌入到allWebDesktop控件区域内&#xff0c;从而实现浏览器内打开各类文档效果。 allWebPlugin中间件是一款为用户提供…...

GitHub Star 数量前 5 的开源应用程序生成器

欢迎来的 GitHub Star 数量排名系列文章的第 7 篇——最受欢迎的应用程序生成器。 之前我们已经详细探讨过&#xff1a;在 GitHub 上最受欢迎的——无代码工具、低代码项目、内部工具、CRUD项目、自部署项目和 Airtable 开源替代品。累计超过 50 个优质项目&#xff01;&#…...

DBC文件当中新建CANFD等类型的报文

同学最近有添加CANFD报文的需求&#xff0c;需要用到CANFD类型报文的DBC文件&#xff0c;这下就难住我了&#xff0c;我之前用的DBC文件只有“CAN Standard”“CAN Extended”两种类型&#xff0c;压根没见过FD的。 后来他找到了项目之前的DBC&#xff0c;打开来看&#xff0c…...

基于SpringBoot的房地产销售管理系统【附源码】

基于SpringBoot的房地产销售管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1用户登录功能的详细实现 4.2管理员权限的功能实现 4.2.1客户信息管理功能的详细实现 4.2.2房产管理功能的详细实现 4.2.3预约看房功能的详细实现 4.2.4论…...

圆点虚线 Android

参考 https://blog.csdn.net/l_o_s/article/details/73550876 <com.xxx.wwww.weight.PointDividerViewandroid:layout_width"match_parent"android:layout_height"wrap_content"app:PDbackgroundColor"color/white"app:dotColor"color/…...

贵州鑫宏远农业-始终致力于推动现代农业的科技创新与发展

贵州鑫宏远农业科技有限公司&#xff0c;是一家在高科技农业领域深耕细作、锐意进取的企业。自成立以来&#xff0c;我们始终致力于推动现代农业的科技创新与发展&#xff0c;业务全面覆盖农业科学研发、组织培养生产、专业育苗培植、半成品及成品精细化养护、市场销售以及全方…...

程序员做销售,从代码到客户的逆袭之路

大家好&#xff0c;我是小悟。 在这个互联网风起云涌、技术迭代日新月异的时代&#xff0c;“跨界”已然成为一种新潮流。就好似那从天而降的大侠&#xff0c;一不小心就可能横跨了数个充满奇遇与挑战的领域。 想象一下&#xff0c;一个平日里只跟代码打交道的程序员&#xf…...

Flink CDC系列之:理解学习Kubernetes模式

Flink CDC系列之&#xff1a;理解学习Kubernetes模式 准备会话模式启动会话集群设置 Flink CDC提交 Flink CDC Job Kubernetes 是一种流行的容器编排系统&#xff0c;用于自动化计算机应用程序的部署、扩展和管理。Flink 的原生 Kubernetes 集成允许您直接在正在运行的 Kuberne…...

git合并相关操作详解

在使用Git进行分支管理时,合并(merge)操作是非常常见的。下面是Git合并相关的详细步骤和一些常见的场景及注意事项。 一、 基本合并操作 假设我们有两个分支:main 和 feature,希望将 feature 合并到 main 上。 切换到目标分支 首先需要切换到你想合并到的分支。例如,切…...

前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等

HTML/CSS 面试题 什么是语义化 HTML&#xff1f; 说明&#xff1a;语义化 HTML 使用 HTML 标签来描述内容的含义&#xff0c;而不仅仅是其外观。使用语义化标签可以提高可读性和可访问性&#xff0c;并对 SEO 友好。示例&#xff1a; <header><h1>网站标题</h1&…...

【Linux知识】linux磁盘管理深入了解

文章目录 常见磁盘管理命令行磁盘分区NASNAS 磁盘挂载&#x1f510; 如何设置NAS设备的访问权限&#xff1f; Mkfs&#x1f9d0; mkfs 命令支持哪些文件系统类型&#xff1f; Mount&#x1f511; 在Linux中&#xff0c;如何安全地卸载挂载的文件系统&#xff1f; 常见磁盘管理命…...

Qt Essential Classes

目录 QVariant QFlags QRandomGenerator 经典的Qt容器 QVector QList QMap QMultiMap QSet QHash QVariant 同std::variant是一样的&#xff0c;他是一个更加高级的union。在一个时间下&#xff0c;它虽然实际上只能是一种类型&#xff0c;但是一个variant可以hold住…...

小小猫棒onu替换家用光猫,薅运营商带宽羊毛,突破1000M

小小猫棒onu 一、总体步骤 1 记录原来光猫信息 主要包括SN&#xff0c;ploam密码&#xff0c;loid、loid密码、 mac、上网的vlan id等 一般gpon采用SN、ploam密码、SNploam密码三种中的一种认证方式 一般Epon采用loid&#xff08;逻辑id&#xff09;、mac、loid mac三种中…...

软件测试学习笔记丨Selenium学习笔记:css定位

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/22511 本文为霍格沃兹测试开发学社的学习经历分享&#xff0c;写出来分享给大家&#xff0c;希望有志同道合的小伙伴可以一起交流技术&#xff0c;一起进步~ 说明&#xff1a;本篇博客基于sel…...

python数据处理常用操作

数据处理是机器学习中非常重要的一步&#xff0c;以下是一些常用的操作和示例代码&#xff1a; 1. 数据清洗 处理缺失值&#xff1a; import pandas as pd# 读取数据 df pd.read_csv(data.csv)# 删除缺失值 df.dropna(inplaceTrue)# 用均值填充缺失值 df.fillna(df.mean(), i…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...