区间动态规划例题:最小成本构造回文串问题(字符插入、删除、替换的通用版本)
字数 1624 2025-12-03 15:23:44

区间动态规划例题:最小成本构造回文串问题(字符插入、删除、替换的通用版本)

题目描述

给定一个字符串 s,你可以进行三种操作:

  1. 插入一个字符,成本为 insertCost
  2. 删除一个字符,成本为 deleteCost
  3. 替换一个字符,成本为 replaceCost(若字符相同,替换成本为0)。

要求通过操作将 s 变成回文串,求最小总成本


解题思路

1. 定义状态

dp[i][j] 表示将子串 s[i:j](左闭右闭区间)变为回文串的最小成本。

2. 状态转移

考虑子串的两端字符 s[i]s[j]

  • 情况1s[i] == s[j]
    两端字符已相同,无需额外操作,直接处理内部子串:
    dp[i][j] = dp[i+1][j-1]

  • 情况2s[i] != s[j]
    需要操作使两端一致,有三种策略:

    1. 在末尾插入一个与 s[i] 相同的字符(使 s[i] 和新增字符匹配),成本为 insertCost + dp[i+1][j]
    2. 删除开头的 s[i](让内部子串与 s[j] 匹配),成本为 deleteCost + dp[i+1][j]
    3. s[i] 替换为 s[j](或反之),成本为 replaceCost + dp[i+1][j-1]

    取三种策略的最小值:
    dp[i][j] = min(insertCost + dp[i+1][j], deleteCost + dp[i+1][j], replaceCost + dp[i+1][j-1])

3. 边界条件

  • 空串或单字符已是回文,成本为0:
    dp[i][i] = 0(单字符)。
    dp[i][i-1] = 0(空串,当 i > j 时视为空串,但本题 i <= j)。

  • 长度为2的子串:
    s[i] == s[i+1]dp[i][i+1] = 0
    否则 dp[i][i+1] = min(replaceCost, insertCost + deleteCost, ...)(需比较所有操作)。


逐步计算示例

s = "abc"insertCost = 1, deleteCost = 1, replaceCost = 1

步骤1:初始化

  • dp[0][0] = dp[1][1] = dp[2][2] = 0(单字符成本为0)。

步骤2:计算长度为2的子串

  • s[0:1] = "ab"

    • 替换:将 a 改为 b(或 b 改为 a),成本=1 + dp[1][0](空串成本0)=1。
    • 插入:在末尾插入 a,成本=1 + dp[0][0]=1;或删除 a,成本=1 + dp[1][1]=1。
    • 最小成本 dp[0][1] = min(1, 1, 1) = 1
  • s[1:2] = "bc":同理 dp[1][2] = 1

步骤3:计算长度为3的子串 s[0:2] = "abc"

  • 两端 s[0]='a' != s[2]='c'
    1. 插入:在末尾插入 a,成本=1 + dp[1][2]=1+1=2。
    2. 删除:删除开头的 a,成本=1 + dp[1][2]=2。
    3. 替换:将 a 改为 c,成本=1 + dp[1][1]=1+0=1。
      dp[0][2] = min(2, 2, 1) = 1

最终最小成本为 dp[0][2] = 1(将 a 替换为 c 得到 "cbc")。


算法实现要点

  1. 按子串长度从小到大计算 dp[i][j]
  2. 注意边界处理(i > j 时成本为0,但循环中 i <= j)。
  3. 时间复杂度 O(n²),空间复杂度 O(n²)。

此方法通用性强,可通过调整成本值适应不同场景。

区间动态规划例题:最小成本构造回文串问题(字符插入、删除、替换的通用版本) 题目描述 给定一个字符串 s ,你可以进行三种操作: 插入 一个字符,成本为 insertCost 。 删除 一个字符,成本为 deleteCost 。 替换 一个字符,成本为 replaceCost (若字符相同,替换成本为0)。 要求通过操作将 s 变成回文串,求 最小总成本 。 解题思路 1. 定义状态 设 dp[i][j] 表示将子串 s[i:j] (左闭右闭区间)变为回文串的最小成本。 2. 状态转移 考虑子串的两端字符 s[i] 和 s[j] : 情况1 : s[i] == s[j] 两端字符已相同,无需额外操作,直接处理内部子串: dp[i][j] = dp[i+1][j-1] 。 情况2 : s[i] != s[j] 需要操作使两端一致,有三种策略: 在末尾插入一个与 s[i] 相同的字符 (使 s[i] 和新增字符匹配),成本为 insertCost + dp[i+1][j] 。 删除开头的 s[i] (让内部子串与 s[j] 匹配),成本为 deleteCost + dp[i+1][j] 。 将 s[i] 替换为 s[j] (或反之),成本为 replaceCost + dp[i+1][j-1] 。 取三种策略的最小值: dp[i][j] = min(insertCost + dp[i+1][j], deleteCost + dp[i+1][j], replaceCost + dp[i+1][j-1]) 。 3. 边界条件 空串或单字符已是回文,成本为0: dp[i][i] = 0 (单字符)。 dp[i][i-1] = 0 (空串,当 i > j 时视为空串,但本题 i <= j )。 长度为2的子串: 若 s[i] == s[i+1] , dp[i][i+1] = 0 ; 否则 dp[i][i+1] = min(replaceCost, insertCost + deleteCost, ...) (需比较所有操作)。 逐步计算示例 设 s = "abc" , insertCost = 1 , deleteCost = 1 , replaceCost = 1 。 步骤1:初始化 dp[0][0] = dp[1][1] = dp[2][2] = 0 (单字符成本为0)。 步骤2:计算长度为2的子串 s[0:1] = "ab" : 替换:将 a 改为 b (或 b 改为 a ),成本=1 + dp[1][0] (空串成本0)=1。 插入:在末尾插入 a ,成本=1 + dp[0][0] =1;或删除 a ,成本=1 + dp[1][1] =1。 最小成本 dp[0][1] = min(1, 1, 1) = 1 。 s[1:2] = "bc" :同理 dp[1][2] = 1 。 步骤3:计算长度为3的子串 s[0:2] = "abc" 两端 s[0]='a' != s[2]='c' : 插入:在末尾插入 a ,成本=1 + dp[1][2] =1+1=2。 删除:删除开头的 a ,成本=1 + dp[1][2] =2。 替换:将 a 改为 c ,成本=1 + dp[1][1] =1+0=1。 dp[0][2] = min(2, 2, 1) = 1 。 最终最小成本为 dp[0][2] = 1 (将 a 替换为 c 得到 "cbc" )。 算法实现要点 按子串长度从小到大计算 dp[i][j] 。 注意边界处理( i > j 时成本为0,但循环中 i <= j )。 时间复杂度 O(n²),空间复杂度 O(n²)。 此方法通用性强,可通过调整成本值适应不同场景。