动态规划算法详解:从基础概念到经典问题解析

发布时间:2026/11/3 21:48:03

动态规划算法详解:从基础概念到经典问题解析 1. 动态规划基础概念解析动态规划(Dynamic Programming)是一种解决复杂问题的算法思想它通过将原问题分解为相对简单的子问题来求解。这种方法特别适用于具有重叠子问题和最优子结构性质的问题。动态规划的核心思想可以概括为三个关键步骤定义状态明确问题的子问题是什么并用状态表示状态转移方程确定状态之间的关系边界条件确定最小子问题的解1.1 动态规划的基本特征动态规划问题通常具备以下两个重要特征最优子结构一个问题的最优解包含其子问题的最优解重叠子问题在递归求解过程中相同的子问题会被多次计算以经典的斐波那契数列为例计算fib(5)需要计算fib(4)和fib(3)而计算fib(4)又需要计算fib(3)和fib(2)这里fib(3)就被重复计算了。1.2 动态规划的两种实现方式动态规划通常有两种实现方式自顶向下的备忘录法记忆化搜索自底向上的迭代法记忆化搜索保留了递归的直观性同时通过存储已计算结果避免重复计算。而迭代法则通常具有更好的空间效率往往能进一步优化空间复杂度。2. 动态规划入门例题详解2.1 爬楼梯问题问题描述假设你正在爬楼梯每次可以爬1或2个台阶。问爬到第n阶有多少种不同的方法。状态定义设dp[i]表示爬到第i阶的方法数状态转移方程 dp[i] dp[i-1] dp[i-2]边界条件 dp[0] 1 dp[1] 1代码实现def climbStairs(n): if n 1: return 1 dp [0] * (n 1) dp[0], dp[1] 1, 1 for i in range(2, n 1): dp[i] dp[i-1] dp[i-2] return dp[n]空间优化由于当前状态只依赖前两个状态可将空间复杂度优化到O(1)def climbStairs(n): if n 1: return 1 a, b 1, 1 for _ in range(2, n 1): a, b b, a b return b2.2 最大子数组和问题问题描述给定一个整数数组nums找到一个具有最大和的连续子数组子数组最少包含一个元素返回其最大和。状态定义dp[i]表示以nums[i]结尾的最大子数组和状态转移方程 dp[i] max(nums[i], dp[i-1] nums[i])边界条件 dp[0] nums[0]代码实现def maxSubArray(nums): n len(nums) dp [0] * n dp[0] nums[0] max_sum dp[0] for i in range(1, n): dp[i] max(nums[i], dp[i-1] nums[i]) max_sum max(max_sum, dp[i]) return max_sum空间优化def maxSubArray(nums): max_sum current_sum nums[0] for num in nums[1:]: current_sum max(num, current_sum num) max_sum max(max_sum, current_sum) return max_sum3. 01背包问题解析3.1 问题描述给定n件物品和一个容量为W的背包。第i件物品的重量为w[i]价值为v[i]。求解将哪些物品装入背包可使这些物品的总重量不超过背包容量且总价值最大。3.2 动态规划解法状态定义dp[i][j]表示前i件物品放入容量为j的背包可以获得的最大价值状态转移方程 dp[i][j] max(dp[i-1][j], dp[i-1][j-w[i]] v[i]) (j w[i])边界条件 dp[0][j] 0 (0 j W) dp[i][0] 0 (0 i n)代码实现def knapsack(W, w, v): n len(w) dp [[0] * (W 1) for _ in range(n 1)] for i in range(1, n 1): for j in range(1, W 1): if j w[i-1]: dp[i][j] max(dp[i-1][j], dp[i-1][j-w[i-1]] v[i-1]) else: dp[i][j] dp[i-1][j] return dp[n][W]3.3 空间优化观察状态转移方程可以发现dp[i][j]只依赖于dp[i-1][...]因此可以优化为一维数组def knapsack(W, w, v): n len(w) dp [0] * (W 1) for i in range(n): for j in range(W, w[i] - 1, -1): dp[j] max(dp[j], dp[j - w[i]] v[i]) return dp[W]注意内层循环必须逆序进行否则会重复计算同一物品多次4. 动态规划解题技巧4.1 识别动态规划问题问题可以分解为若干子问题子问题之间有重叠具有最优子结构性质4.2 解题步骤定义状态明确dp数组的含义确定状态转移方程找出状态之间的关系初始化边界条件确定计算顺序考虑空间优化4.3 常见错误与调试技巧数组越界特别注意边界条件的处理状态转移方程错误通过小规模测试用例验证空间优化时的顺序错误如01背包问题必须逆序更新初始化不当确保所有可能的状态都被正确初始化4.4 经典问题分类线性DP最长递增子序列、最大子数组和等区间DP矩阵链乘法、石子合并等背包问题01背包、完全背包、多重背包等树形DP在树结构上的动态规划状态压缩DP使用位运算表示状态5. 动态规划进阶例题5.1 最长递增子序列(LIS)问题描述给定一个无序的整数数组找到其中最长严格递增子序列的长度。状态定义dp[i]表示以nums[i]结尾的最长递增子序列长度状态转移方程 dp[i] max(dp[j] 1) for all j i and nums[j] nums[i]代码实现def lengthOfLIS(nums): if not nums: return 0 dp [1] * len(nums) for i in range(1, len(nums)): for j in range(i): if nums[j] nums[i]: dp[i] max(dp[i], dp[j] 1) return max(dp)优化解法O(nlogn)的贪心二分查找算法def lengthOfLIS(nums): tails [] for num in nums: left, right 0, len(tails) while left right: mid (left right) // 2 if tails[mid] num: left mid 1 else: right mid if left len(tails): tails.append(num) else: tails[left] num return len(tails)5.2 编辑距离问题描述给定两个单词word1和word2计算将word1转换成word2所使用的最少操作数。操作包括插入、删除、替换字符。状态定义dp[i][j]表示word1前i个字符转换为word2前j个字符的最小操作数状态转移方程 如果word1[i-1] word2[j-1]: dp[i][j] dp[i-1][j-1] 否则: dp[i][j] min( dp[i-1][j] 1, # 删除 dp[i][j-1] 1, # 插入 dp[i-1][j-1] 1 # 替换 )代码实现def minDistance(word1, word2): m, n len(word1), len(word2) dp [[0] * (n 1) for _ in range(m 1)] for i in range(m 1): dp[i][0] i for j in range(n 1): dp[0][j] j for i in range(1, m 1): for j in range(1, n 1): if word1[i-1] word2[j-1]: dp[i][j] dp[i-1][j-1] else: dp[i][j] min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) 1 return dp[m][n]6. 动态规划常见问题解答6.1 如何判断一个问题是否适合用动态规划解决检查问题是否可以分解为子问题验证是否具有最优子结构性质确认是否存在重叠子问题尝试写出递归关系式6.2 动态规划与分治法的区别是什么分治法将问题分解为互不重叠的子问题而动态规划处理的是有重叠的子问题。动态规划通过记忆化存储避免了重复计算。6.3 如何优化动态规划的空间复杂度观察状态转移方程看当前状态是否只依赖于有限的前驱状态使用滚动数组技术对于多维DP考虑是否可以降低维度6.4 动态规划的时间复杂度如何分析通常时间复杂度 状态数 × 每个状态的转移次数。例如二维DP表大小为n×m每个状态转移需要O(1)时间则总时间复杂度为O(nm)。7. 动态规划实战技巧7.1 状态设计技巧根据问题特点选择合适的状态表示有时需要增加状态维度来满足无后效性对于复杂问题可以先用递归思路再转化为DP7.2 边界条件处理明确最小子问题的解考虑空集、零值等特殊情况初始化时注意数组大小和初始值7.3 调试方法打印DP表观察中间结果使用小规模测试用例验证对比递归解和迭代解的结果7.4 性能优化减少不必要的状态转移利用数学性质简化状态转移方程考虑是否可以贪心或二分查找优化在实际应用中动态规划往往需要结合具体问题特点进行灵活调整。掌握核心思想后通过大量练习可以逐渐培养出解决问题的直觉。
延伸阅读

更多相关文章

2026/11/3 21:48:03

ESP32-C3 DNS过滤实战:封禁设备、暂停拦截与自定义域名

家里网络里挂一台 ESP32-C3 做 DNS 层面的去广告,这个方案我前后用了小半年,最大感受是:真正决定这套东西好不好用的,不是拦截列表有多大,而是封禁设备、暂停拦截、自定义域名这三件日常操作顺不顺手。装好第一天你会觉…

2026/11/3 21:43:02

MCP协议逆向工程实战:从抓包到Wireshark解析

1. 项目概述:当“逆向工程”撞上“MCP”,热榜登顶背后的真实图景“GitHub今日热榜 | 2026-10-08:逆向工程 MCP 登顶”——这个标题乍看像一则技术快讯,但拆开来看,它其实是一把钥匙,能打开当前软件开发、安…

2026/11/3 21:43:02

老旧系统现代化改造:从补丁困境到集成破局

1. 旧系统补丁困境:一场注定失败的消耗战 每次看到企业IT部门还在给那些服役超过10年的老旧OA/ERP系统打补丁,我就想起给漏水的木桶不断缠胶带的场景。上周遇到某制造业客户,他们的ERP系统光是今年就已经打了27个补丁——这相当于每周都在系统…

2026/11/3 22:38:11

VR驾驶模拟器在智能座舱HMI设计中的关键技术解析

1. VR驾驶模拟器与智能座舱的融合创新最近在汽车HMI(人机交互)领域,VR驾驶模拟器正成为智能座舱研发的标配工具。这套系统本质上是一个虚实结合的人机工效验证平台,通过头显设备、力反馈方向盘和六自由度运动平台,构建…

2026/11/3 22:38:11

JavaScript模块化:CommonJS与ES Module对比与实践

1. 模块化规范的必要性 在早期的JavaScript开发中&#xff0c;代码组织方式简单粗暴 - 通过 <script> 标签引入多个JS文件。这种方式带来了三大致命问题&#xff1a; 命名冲突 &#xff1a;全局作用域下的函数和变量会相互覆盖。比如两个文件都定义了 calculate() …

2026/11/3 22:38:11

Buzz传播三触点:截屏、搜索、UGC再创作

1. “buzz”不是随便起的网名&#xff0c;它是一套正在被低估的传播信号系统最近在几个技术社区和创意工作坊里&#xff0c;我反复听到这个词被当作动词用&#xff1a;“这个功能上线后得先造点buzz”&#xff0c;“那个视频没buzz起来&#xff0c;数据就卡在3000播放不动了”。…

2026/11/3 22:38:11

Hindsight复盘系统:用决策日志把经验变成未来决策依据

1. 从“hindsight”说起&#xff1a;一个被低估的复盘工具 “hindsight”这个词&#xff0c;直译过来就是“后见之明”。但在实际的项目管理和个人成长场景里&#xff0c;它远不止一个简单的英文单词。我第一次接触这个概念&#xff0c;是在一个跨部门项目复盘会上&#xff0c;…

2026/11/3 22:38:11

SAP基金管理:承诺预算与可用性检查配置排查

简介&#xff1a;《SAP基金管理功能详解》面向SAP财务与预算管理实施人员、顾问及关键用户&#xff0c;聚焦基金管理中的预算控制逻辑与业务集成方式&#xff0c;帮助读者理清基金中心、基金与承诺项目的组织关系及预算执行链路。压缩包仅含1个doc文档&#xff0c;约94KB&#…

2026/11/3 22:33:11

基于MCP与Docker构建LLM Agent持久化记忆系统:从hindsight到工程落地

1. 从“hindsight”说起&#xff1a;为什么Agent的记忆问题值得单独拎出来做“hindsight”这个词本身挺有意思&#xff0c;字面意思是“事后的聪明”&#xff0c;也就是回头看的时候才明白当时该怎么做。放在LLM Agent的语境里&#xff0c;它指向一个非常具体的痛点&#xff1a…

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代&#xff0c;基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而&#xff0c;与配合度高的人类不同&#xff0c;宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态&#xff0c;更无法控制光照环境。实际应用中&#xff0c;我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32实战:基于MAX14431数字隔离器的SPI隔离通信方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

工业SPI隔离通信设计:MAX14431BAEE+与STM32L4A6RG实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32+NRF24L01无线抢答器:硬件设计、通信协议与低功耗实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代&#xff0c;基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而&#xff0c;与配合度高的人类不同&#xff0c;宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态&#xff0c;更无法控制光照环境。实际应用中&#xff0c;我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑