1. 动态规划专题训练概述
今天进入算法训练营的第38天,我们继续深入动态规划这个既让人爱又让人恨的话题。经过前五天的专题训练,相信大家对动态规划的基本框架和经典题型已经有了初步认识。今天的专题6将聚焦几个更具挑战性的问题类型,包括背包问题的变种、股票买卖系列以及字符串编辑距离等实际工程中常见的问题场景。
动态规划之所以让很多初学者感到困难,核心在于其"看似简单实则暗藏玄机"的特性。一个合格的动态规划解法需要同时满足三个关键条件:最优子结构、无后效性和重叠子问题。在实际解题过程中,我们常常会遇到状态定义模糊、转移方程难以建立、边界条件处理不当等典型问题。
重要提示:动态规划专题建议按照"五步法"系统练习:1.明确dp数组定义 2.确定递推公式 3.初始化dp数组 4.确定遍历顺序 5.举例推导验证
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 背包问题进阶解析
2.1 完全背包与01背包的本质区别
完全背包问题是今天训练的重点内容之一。与基础的01背包不同,完全背包中每种物品可以选取无限次,这个看似微小的变化却带来了解法上的本质差异。让我们通过代码对比来理解这两种背包问题的核心区别:
python复制# 01背包核心代码(物品在外层,容量在内层,且容量倒序遍历)
for i in range(len(weight)):
for j in range(bagWeight, weight[i] - 1, -1):
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
# 完全背包核心代码(物品在外层,容量在内层,但容量正序遍历)
for i in range(len(weight)):
for j in range(weight[i], bagWeight + 1):
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
关键差异点在于内层循环的遍历方向:01背包必须倒序以避免重复选取,而完全背包则需要正序以实现多次选取。这个细节在实际面试中经常被考察,也是容易出错的地方。
2.2 背包问题的排列与组合
背包问题在实际应用中还有两个重要变种:求排列数(考虑顺序)和求组合数(不考虑顺序)。这两种情况的状态转移方程看似相似,但遍历顺序却有本质不同:
- 组合问题(如零钱兑换):外层遍历物品,内层遍历容量
- 排列问题(如爬楼梯):外层遍历容量,内层遍历物品
以LeetCode 518.零钱兑换II(组合)和70.爬楼梯(排列)为例:
python复制# 组合问题解法
def change(amount, coins):
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins
