最长共用子序列问题LCS(Python实现)

为了统一化操作且不越界,保证s的长度小于t的长度。内部循环比较过程中,若相等,则为pre[ni-1]+1,否则为pre[ni]与cur[ni-1]的最大值。

def longest_common_sub(s, t):
    if len(s) > len(t):
        s, t = t, s
    n, m = len(s), len(t)
    pre, cur = [0]*(n+1), [0]*(m+1)
    for mi in range(1, m+1):
        pre, cur = cur, pre
        for ni in range(1, n+1):
            if s[ni-1] == t[mi-1]:
                cur[ni] = pre[ni-1]+1
            else:
                cur[ni] = max(cur[ni-1], pre[ni])
    return cur[-1]


s, t = 'watkins', 'watson'
print(longest_common_sub(s, t))     # 4

(最近更新:2019年09月06日)

动态规划背包问题分类与解决方案总结 背包问题是组合优化领域经典问题,核心目标为:给定容量限制的背包与若干带“消耗属性”(如重量、体积)和“价值属性”的物品,通过合理选物品使总价值最大化,且总消耗不超背包容量。按物品选取规则、约束条件可分为7类核心场景,以下从核心特点、数学模型、DP解法(含状态定义、转移方程)、优化技巧、适用场景展开详细总结。 一、0-1背包问题(基础核心) 1. 核心特点 每个物品仅能选或不选(二选一,无中间状态),不可重复选取、不可分割。 2. 数学模型 - 输入:n个物品,物品i的消耗(如重量) w_i 、价值 v_i ;背包最大容量 W 。 - 决策变量: x_i \in \{0,1\} ( x_i=1 选物品i, x_i=0 不选)。 - 目标函数:最大化总价值 \max \sum_{i=1}^n v_i x_i 。 - 约束条件:总消耗不超容量 \sum_{i=1}^n w_i x_i \leq W 。 3. DP解法 (1)二维DP(原始版,无空间优化) - 状态定义: dp[i][j] 表示前i个物品中选,背包容量为j时的最大价值。 - 转移方程: dp[i][j] = \begin{cases} dp[i-1][j] & (j < w_i,无法选物品i) \\ \max(dp[i-1][j], dp[i-1][j-w_i] + v_i) & (j \geq w_i,选/不选物品i取最大值) \end{cases} - 初始化: dp[0][j]=0 (前0个物品,价值恒为0)、 dp[i][0]=0 (容量为0,无法选物品,价值恒为0)。 - 时间复杂度: O(nW) ,空间复杂度: O(nW) 。 (2)一维DP(空间优化版,常用) - 核心逻辑:二维DP中 dp[i][j] 仅依赖 dp[i-1][\cdot] ,可压缩为一维数组,通过“逆序遍历容量”避免重复选同一物品。 - 状态定义: dp[j] 表示背包容量为j时的最大价值。 - 转移方程: dp[j] = \max(dp[j], dp[j-w_i] + v_i) \quad (j从W逆序遍历至w_i) - 初始化: dp[0]=0 ,其余 dp[j]=0 (或负无穷,视是否允许“空选”调整)。 - 时间复杂度: O(nW) ,空间复杂度: O(W) 。 4. 扩展:统计选法方案数 - 目标:统计“总消耗≤j且总价值达标”(或仅“总消耗=j”)的选法数量,不关注价值大小。 - 转移方程: dp[j] += dp[j-w_i] (j从W逆序遍历至w_i)。 - 初始化: dp[0]=1 (容量0时,“不选任何物品”为1种方案),其余 dp[j]=0 。 5. 适用场景 物品不可重复、数量少(n≤1000)、容量适中(W≤1e4),如“物品选/不选的价值最大化”。 二、完全背包问题 1. 核心特点 每个物品可无限次选取(无数量限制),仅受背包容量约束。 2. 数学模型 - 输入、目标函数、约束条件同0-1背包,仅决策变量调整: x_i \in \{0,1,2,...\} (非负整数,可重复选)。 3. DP解法 (1)二维DP(原始版) - 状态定义:同0-1背包 dp[i][j] (前i个物品、容量j的最大价值)。 - 转移方程: dp[i][j] = \begin{cases} dp[i-1][j] & (j < w_i,无法选物品i) \\ \max(dp[i-1][j], dp[i][j-w_i] + v_i) & (j \geq w_i,选物品i后可继续选同一物品) \end{cases} - 时间复杂度: O(nW) ,空间复杂度: O(nW) 。 (2)一维DP(空间优化版,常用) - 核心逻辑:允许重复选物品,故“正序遍历容量”(选当前物品后,后续容量可复用该物品)。 - 状态定义:同0-1背包一维版 dp[j] 。 - 转移方程: dp[j] = \max(dp[j], dp[j-w_i] + v_i) \quad (j从w_i正序遍历至W) - 初始化: dp[0]=0 ,其余 dp[j]=0 。 - 时间复杂度: O(nW) ,空间复杂度: O(W) 。 4. 数学优化(辅助技巧) 计算物品单位消耗价值 \frac{v_i}{w_i} ,优先选性价比高的物品,可快速得到近似最优解;但因容量可能无法整除消耗,需结合DP修正精确解。 5. 扩展:统计选法方案数 - 转移方程: dp[j] += dp[j-w_i] (j从w_i正序遍历至W)。 - 初始化: dp[0]=1 ,其余 dp[j]=0 。 6. 适用场景 物品可重复使用,如“硬币兑换(不限硬币数量,凑指定金额)”“材料无限,制作物品价值最大化”。 三、多重背包问题 1. 核心特点 每个物品有固定数量限制 c_i (最多选 c_i 个),介于0-1背包( c_i=1 )与完全背包( c_i→∞ )之间。 2. 数学模型 - 输入、目标函数、约束条件同前,决策变量调整: x_i \in \{0,1,...,c_i\} (选数≤物品上限)。 3. DP解法 (1)直接法(暴力枚举,不推荐) - 状态定义: dp[j] (容量j的最大价值)。 - 转移方程: dp[j] = \max(dp[j], dp[j-k \cdot w_i] + k \cdot v_i) \quad (0 \leq k \leq c_i,且j \geq k \cdot w_i) - 时间复杂度: O(nW \sum c_i) ,效率极低,仅适用于 c_i 极小场景。 (2)二进制优化(常用,高效) - 核心逻辑:将物品数量 c_i 拆分为 \log_2 c_i 个“新物品”(如 c_i=5 拆为1、2、2, c_i=7 拆为1、2、4),新物品重量=原重量×拆分系数,价值=原价值×拆分系数,转化为0-1背包求解(新物品选/不选对应原物品选对应数量)。 - 转移方程:复用0-1背包一维DP方程( dp[j] = \max(dp[j], dp[j-w_{新}] + v_{新}) ,j逆序遍历)。 - 时间复杂度: O(nW \log c_i) ,空间复杂度: O(W) ,适配多数场景。 (3)单调队列优化(极限优化,大数据量) - 核心逻辑:通过滑动窗口维护“容量j附近可选取的最优价值”,消除枚举k的冗余步骤,将时间复杂度降至线性。 - 转移方程推导:对容量j按 j \mod w_i = r 分组(r=0,1,...,w_i-1),每组内 j = r + t \cdot w_i ,方程转化为: dp[r + t \cdot w_i] = \max(dp[r + (t-k) \cdot w_i] + k \cdot v_i) \quad (0 \leq k \leq \min(c_i, t)) 用单调队列维护 dp[r + (t-k) \cdot w_i] - (t-k) \cdot v_i 的最大值,直接取队首更新当前dp值。 - 时间复杂度: O(nW) ,空间复杂度: O(W) ,适用于 W≥1e5 的大数据场景。 4. 扩展:统计选法方案数 - 二进制优化后复用0-1背包方案数方程,直接法复用枚举k的累加方程( dp[j] += dp[j-k \cdot w_i] )。 - 初始化: dp[0]=1 ,其余 dp[j]=0 。 5. 适用场景 物品有数量限制,如“商品限购、材料库存有限,选物品价值最大化”。 四、混合背包问题 1. 核心特点 同一问题中同时包含0-1背包物品(选1次)、完全背包物品(选无限次)、多重背包物品(选有限次),需分类型处理物品。 2. 解法核心 - 分类适配策略: 1. 0-1背包物品:直接用一维DP逆序遍历容量更新; 2. 完全背包物品:直接用一维DP正序遍历容量更新; 3. 多重背包物品:先二进制拆分(或单调队列优化),转化为0-1背包后逆序遍历更新。 - 状态定义: dp[j] (容量j的最大价值),全局共用一个DP数组。 - 转移方程:按物品类型复用对应背包的一维转移方程,遍历顺序为“先遍历物品→再按类型遍历容量”。 3. 时间复杂度 取决于各类物品占比,整体为 O(nW + n_多 W \log c_i) ( n_多 为多重背包物品数量),空间复杂度 O(W) 。 4. 适用场景 多类型物品共存,如“购物时部分商品限购、部分不限购、部分仅一件”。 五、分组背包问题 1. 核心特点 物品按类别分组,每组内至少选0个、最多选1个物品(组间独立,组内互斥)。 2. 数学模型 - 输入:m组物品,第k组含 s_k 个物品,组内物品i的消耗 w_{k,i} 、价值 v_{k,i} ;背包容量 W 。 - 决策变量:每组内仅1个物品 x_{k,i}=1 (或全为0),其余 x_{k,i}=0 。 - 目标函数: \max \sum_{k=1}^m \sum_{i=1}^{s_k} v_{k,i} x_{k,i} ,约束条件: \sum_{k=1}^m \sum_{i=1}^{s_k} w_{k,i} x_{k,i} \leq W 。 3. DP解法 - 核心逻辑:先遍历组→再逆序遍历容量(避免组内选多个物品)→最后遍历组内物品,按“选组内某物品/不选组内任何物品”更新DP。 - 状态定义: dp[j] (容量j的最大价值)。 - 转移方程: dp[j] = \max(dp[j], dp[j-w_{k,i}] + v_{k,i}) \quad (先遍历组k→j从W逆序至w_{k,i}→遍历组k内物品i) - 初始化: dp[0]=0 ,其余 dp[j]=0 。 - 时间复杂度: O(mW \bar{s}) ( \bar{s} 为每组平均物品数),空间复杂度 O(W) 。 4. 扩展:统计选法方案数 - 转移方程: dp[j] += dp[j-w_{k,i}] (遍历顺序同上,j逆序)。 - 初始化: dp[0]=1 ,其余 dp[j]=0 。 5. 适用场景 物品分组且组内互斥,如“考试选做题(每组1道,选1道或不选)、套餐选择(每组1个套餐,选1个或不选)”。 六、二维费用背包问题 1. 核心特点 物品需消耗两类资源(如重量+体积、重量+金额),背包对两类资源均有容量限制(如背包限重W、限体积V),分0-1型与完全型。 2. 数学模型(以0-1型为例) - 输入:n个物品,物品i消耗资源1 w_{i1} 、资源2 w_{i2} ,价值 v_i ;背包资源1容量 W 、资源2容量 V 。 - 目标函数: \max \sum_{i=1}^n v_i x_i ,约束条件: \sum_{i=1}^n w_{i1} x_i \leq W 、 \sum_{i=1}^n w_{i2} x_i \leq V , x_i \in \{0,1\} 。 3. DP解法 (1)二维DP(原始版) - 状态定义: dp[i][j][k] 表示前i个物品、资源1容量j、资源2容量k时的最大价值。 - 转移方程(0-1型): dp[i][j][k] = \begin{cases} dp[i-1][j][k] & (j < w_{i1} 或 k < w_{i2}) \\ \max(dp[i-1][j][k], dp[i-1][j-w_{i1}][k-w_{i2}] + v_i) & (j \geq w_{i1} 且 k \geq w_{i2}) \end{cases} - 时间复杂度: O(nWV) ,空间复杂度: O(nWV) 。 (2)二维滚动数组(空间优化版,常用) - 核心逻辑:压缩物品维度,用二维数组 dp[j][k] 表示资源1容量j、资源2容量k的最大价值,0-1型需“双逆序遍历资源”,完全型需“双正序遍历资源”。 - 转移方程(0-1型): dp[j][k] = \max(dp[j][k], dp[j-w_{i1}][k-w_{i2}] + v_i) \quad (j从W逆序至w_{i1},k从V逆序至w_{i2}) - 转移方程(完全型): dp[j][k] = \max(dp[j][k], dp[j-w_{i1}][k-w_{i2}] + v_i) \quad (j从w_{i1}正序至W,k从w_{i2}正序至V) - 初始化: dp[0][0]=0 ,其余 dp[j][k]=0 。 - 时间复杂度: O(nWV) ,空间复杂度: O(WV) 。 4. 适用场景 物品消耗多类资源,如“行李箱限重且限体积,选物品价值最大化”“项目限资金且限时间,选任务收益最大化”。 七、背包问题通用总结 1. 核心共性 - 本质:通过DP存储“局部容量下的最优价值/方案数”,避免重复计算,核心是“状态定义+转移逻辑”; - 空间优化优先级:二维DP→一维滚动数组(单/多资源维度),优先压缩物品维度; - 时间优化核心:减少冗余枚举(如二进制拆分消除k枚举、单调队列优化滑动窗口)。 2. 关键差异对比表 背包类型 物品选取规则 核心遍历顺序 核心优化技巧 时间复杂度 核心场景 0-1背包 选1次或不选 容量逆序 一维滚动数组   物品不可重复 完全背包 无限次选 容量正序 一维滚动数组   物品可重复使用 多重背包 最多选 次 逆序(拆分后) 二进制拆分、单调队列   物品有数量限制 混合背包 0-1+完全+多重共存 分类型定顺序 分类适配 适配多类型复杂度 多规则物品共存 分组背包 组内最多选1个 组→逆序容量→组内物品 组内遍历控制   物品分组且组内互斥 二维费用背包 消耗两类资源,选1次/无限次 双资源逆序/正序 二维滚动数组   物品消耗多类资源 3. 解题步骤 1. 明确物品类型(选法规则、消耗资源数)与背包约束(容量/资源上限); 2. 定义DP状态(单/多维度,对应资源容量,明确存储含义:价值/方案数); 3. 推导转移方程(按“选/不选当前物品”拆分,适配选取规则); 4. 确定初始化值(按“空容量/空物品”场景赋值,方案数必设 dp[0...]=1 ); 5. 优化空间/时间(优先一维数组,大数据量补二进制/单调队列优化); 6. 验证边界(如容量不足、物品数量为0的极端场景)。 通过以上分类与解法,可覆盖绝大多数背包问题场景,核心是掌握“选法规则→遍历顺序→优化技巧”的对应关系,灵活适配具体需求。 帮我补充修改
最新发布
11-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值