最长重复子数组的变种:最多允许k次替换的最长公共子数组(进阶版:替换代价为权重,限制替换操作总代价不超过C)
字数 6270 2025-12-22 20:32:21

最长重复子数组的变种:最多允许k次替换的最长公共子数组(进阶版:替换代价为权重,限制替换操作总代价不超过C)

题目描述
给定两个整数数组 nums1nums2,以及一个非负整数 k 和一个正整数 C。我们允许在匹配子数组时,最多进行 k 次“替换”操作,每次替换操作可以将 nums1 中某个位置的值改为任意整数(即与 nums2 中对应位置的值匹配),但每次替换操作有一个正整数代价(由给定的代价函数决定)。替换操作的总代价不能超过 C。我们需要找到最长的公共子数组长度,使得在满足替换次数不超过 k 且替换总代价不超过 C 的条件下,nums1 的一个子数组与 nums2 的一个子数组完全相同。

注意

  • 子数组必须是连续的。
  • 替换操作只能用于 nums1 中的元素(或对称地用于 nums2,但题目通常约定修改一个数组)。
  • 代价函数可以简化:假设代价为被替换元素的“改变量”的绝对值,即 abs(nums1[i] - newValue),但 newValue 必须等于 nums2[j],因此单次替换代价为 abs(nums1[i] - nums2[j])
  • 题目是经典“最多允许k次替换的最长重复子数组”的增强版,增加了代价限制,使得问题更接近实际匹配中的容错匹配。

解题步骤
这是一个二维动态规划问题,但状态需要额外记录替换次数和当前代价。为了降低复杂度,我们可以采用 滑动窗口 + 动态规划优化三维DP。下面我将详细解释三维DP解法,因为其思路更直观,便于理解状态转移。

定义状态
dp[i][j][c] 表示以 nums1[i-1]nums2[j-1] 结尾的公共子数组,在使用了恰好 c 次替换操作时的最小替换代价。但这样定义会导致状态数过大(因为代价维度是C)。更好的方法是将“代价”视为资源限制,用状态记录替换次数,并在转移时检查代价是否允许。

我们定义状态为:
dp[i][j][k_used] 表示以 nums1[i-1]nums2[j-1] 结尾的公共子数组的长度,其中已经使用了 k_used 次替换操作,并且替换总代价不超过 C 的最大长度。但“长度”不适合直接做DP值,因为长度是我们要最大化的目标。我们可以转换思路:用 dp[i][j][k_used] 表示“以nums1[i-1]和nums2[j-1]结尾的公共子数组,在使用了k_used次替换时的最小总代价”,然后在所有代价 ≤ C 的状态中找最长的子数组长度。

但这样依然复杂。更实用的方法是:用二维DP + 第三维为替换次数,并在状态转移时累积代价,但代价累积后我们只关心是否 ≤ C。由于代价是累加的,我们可以在递推过程中计算代价,并只保留那些代价 ≤ C 的状态。

简化:假设代价是每次替换固定的(比如每次替换代价=1),那么只需记录替换次数即可,原题是“最多允许k次替换的最长公共子数组”,经典解法是滑动窗口或DP。但这里代价可变,我们需要调整。


重新规划状态
dp[i][j][k_used] 表示以 nums1[i-1]nums2[j-1] 结尾的公共子数组,在使用恰好 k_used 次替换时的最小累计代价。如果无法形成这样的子数组,代价设为无穷大(INF)。
状态转移方程分两种情况:

  1. 如果 nums1[i-1] == nums2[j-1],则不需要替换:
    dp[i][j][k_used] = dp[i-1][j-1][k_used](继承之前的代价)
    但前提是 i>1j>1dp[i-1][j-1][k_used] != INF,否则如果 i==1j==1,则这是一个新的子数组起点,代价为0。

  2. 如果 nums1[i-1] != nums2[j-1],则可以选择替换(如果 k_used > 0):
    替换代价增加 abs(nums1[i-1] - nums2[j-1]),所以:
    dp[i][j][k_used] = dp[i-1][j-1][k_used-1] + cost
    其中 cost = abs(nums1[i-1] - nums2[j-1])
    同样,如果 i==1j==1,则之前代价为0。

  3. 初始条件:当 i=0 或 j=0 时,不存在以它结尾的子数组,我们可以不考虑这些状态,直接从 i=1,j=1 开始递推。但为了方便,我们可以将 dp[0][*][*]dp[*][0][*] 设为 INF,除了 dp[0][0][0]=0 这种虚拟状态。不过通常我们初始化每个 (i,j) 时,如果 nums1[i-1]==nums2[j-1],则 dp[i][j][0]=0,否则 dp[i][j][1]=cost(如果k>=1)。

但这样定义 dp 值为代价,我们怎么得到最长长度?
我们需要另一个数组 len[i][j][k_used] 记录长度。但可以简化:因为 dp 值记录最小代价,只要 dp 值 ≤ C,就说明这个子数组可行,其长度就是当前连续匹配的长度,这个长度可以在递推时累积。

更好的方法:不记录代价在状态值里,而是将代价作为第四维,但那样状态太多。我们换个思路:


优化思路:二分答案 + 二维DP检查
我们可以二分查找最长长度 L,然后检查是否存在长度为 L 的公共子数组,使得替换次数 ≤ k 且替换总代价 ≤ C。
如何检查?
对于给定的长度 L,我们可以枚举所有起始位置 i 在 nums1,j 在 nums2,然后计算从 (i, j) 开始的长度为 L 的子数组的替换次数和总代价。但这样是 O(n1n2L) 的。
我们可以用前缀和优化
先预处理 diff[i][j] = abs(nums1[i] - nums2[j]),然后对每个对齐位置偏移 p = i-j,在对应对齐的斜线上,用滑动窗口维护窗口内 diff 的和,找到窗口内 diff 的和 ≤ C 且窗口内非零 diff 的数量 ≤ k 的最大窗口长度。但这要枚举偏移 p,复杂度 O((n1+n2)*n1) 左右,稍复杂。

但更通用的检查方法是DP
定义 f[i][j] 表示以 nums1[i] 和 nums2[j] 结尾的公共子数组,在替换代价 ≤ C 的前提下,最少替换次数。
但这里“替换次数最少”和“代价 ≤ C”是双重约束,我们可以反过来:在替换次数 ≤ k 下,最小化代价,看是否 ≤ C。
这可以通过二维DP,状态是 (i,j,used),used 是替换次数,值为最小代价,然后看 used ≤ k 中是否有代价 ≤ C 的。
不过二分长度 L 后,我们只需判断是否存在长度 ≥ L 的子数组,这可以通过计算每个 (i,j) 结尾的最长匹配(满足代价约束)是否 ≥ L 来判断。


最终采用的DP解法(三维DP,记录长度)
我们设 dp[i][j][c] 表示以 nums1[i-1] 和 nums2[j-1] 结尾的公共子数组,在替换总代价恰好为 c 时的最大长度(c 从 0 到 C)。
初始化:dp 全为 0。
转移方程:
如果 nums1[i-1] == nums2[j-1]:
对于每个 c 从 0 到 C:
dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c] + 1)(如果 i>1 且 j>1),否则 dp[i][j][c]=1(当 i=1 或 j=1 时单独处理)。

如果 nums1[i-1] != nums2[j-1],设 cost = abs(nums1[i-1] - nums2[j-1]):
对于每个 c 从 cost 到 C:
dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c-cost] + 1)(前提是 dp[i-1][j-1][c-cost] > 0 或 c==cost 且 i-1==0 或 j-1==0 时长度为1)。

注意:c 维度是代价,我们要让长度最大,所以 dp 值存储长度。
最后答案就是所有 i, j, c ≤ C 中 dp[i][j][c] 的最大值。

复杂度:O(n1 * n2 * C),C 是代价上限,如果 C 很大,此法不可行。但在很多实际问题中 C 是较小的整数。


例子说明
设 nums1 = [1,3,5], nums2 = [3,1,5], k=1, C=2。
代价函数:cost = abs(nums1[i]-nums2[j])。
我们尝试 dp 过程:
初始化 dp 全 0。
i=1, j=1: nums1[0]=1, nums2[0]=3, 不等,cost=2,c=2 时 dp[1][1][2]=1。
i=1, j=2: 1 和 1 相等,c=0 时 dp[1][2][0]=1。
i=1, j=3: 1 和 5 不等,cost=4>2,忽略(代价超)。
i=2, j=1: 3 和 3 相等,c=0 时 dp[2][1][0]=max(0, dp[1][0][0]+1),但 dp[1][0][0] 不存在,视为0,所以长度=1。
i=2, j=2: 3 和 1 不等,cost=2,c=2 时 dp[2][2][2]=max(0, dp[1][1][0]+1),但 dp[1][1][0]=0,所以长度=1。
i=2, j=3: 3 和 5 不等,cost=2,c=2 时 dp[2][3][2]=max(0, dp[1][2][0]+1),而 dp[1][2][0]=1,所以长度=2。
i=3, j=1: 5 和 3 不等,cost=2,c=2 时 dp[3][1][2]=max(0, dp[2][0][0]+1)=1。
i=3, j=2: 5 和 1 不等,cost=4>2,忽略。
i=3, j=3: 5 和 5 相等,c=0 时 dp[3][3][0]=dp[2][2][0]+1,但 dp[2][2][0]=0,所以长度=1。

最后检查所有 dp 值,最大长度是 dp[2][3][2]=2,即子数组 nums1[1..2]=[3,5] 与 nums2[2..3]=[1,5] 在替换 nums1[1] 从3改为1(代价2)后相同。
但这里替换次数是1(k=1满足),代价=2(C=2满足),所以答案是2。


总结步骤

  1. 确定代价计算方式(本题为绝对值差)。
  2. 定义三维数组 dp[i][j][c] 表示以 nums1[i-1] 和 nums2[j-1] 结尾的公共子数组,在总替换代价为 c 时的最大长度。
  3. 初始化 dp 为0。
  4. 遍历 i 从 1 到 n1,j 从 1 到 n2:
    • 如果两数相等,则对每个 c 从 0 到 C:若 dp[i-1][j-1][c] 有值,则 dp[i][j][c] = dp[i-1][j-1][c]+1;否则若 i=1 或 j=1,则 dp[i][j][c]=1。
    • 如果两数不等,计算 cost,对每个 c 从 cost 到 C:若 dp[i-1][j-1][c-cost] 有值,则 dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c-cost]+1);否则若 i=1 或 j=1 且 c==cost,则 dp[i][j][c]=1。
  5. 最终答案为所有 dp[i][j][c] 的最大值,且满足替换次数 ≤ k 吗?等等,我们还没记录替换次数!
    问题:我们只记录了总代价,没记录替换次数。所以需增加一维记录替换次数,变为四维 dp[i][j][c][r]:代价 c,替换次数 r 时的最大长度,但这样状态太大。

调整:既然替换次数 ≤ k 且代价 ≤ C,我们可以将代价视为“资源”,记录最少替换次数达到某个代价的状态,但更直接的方法是:
用 dp[i][j][r] 表示以 nums1[i-1] 和 nums2[j-1] 结尾的公共子数组,在替换次数为 r 时的最小总代价。
然后如果 dp[i][j][r] ≤ C,则其对应的长度可以由另一个数组 len[i][j][r] 记录。
转移:
若 nums1[i-1]==nums2[j-1],则 dp[i][j][r] = dp[i-1][j-1][r],len=len[i-1][j-1][r]+1。
若不相等,则 dp[i][j][r] = dp[i-1][j-1][r-1] + cost,len=len[i-1][j-1][r-1]+1(若 r>0)。
初始化:dp[0][][]=INF,dp[][0][]=INF,dp[0][0][0]=0,len[0][0][0]=0。
最后,找出所有 r ≤ k 且 dp[i][j][r] ≤ C 的 len[i][j][r] 的最大值。
复杂度 O(n1n2k),可行。


最终算法

  1. 初始化 dp[n1+1][n2+1][k+1] 为无穷大,len[n1+1][n2+1][k+1]=0。
  2. dp[0][0][0]=0, len[0][0][0]=0。
  3. 遍历 i 从 0 到 n1,j 从 0 到 n2(i,j 不同时为0):
    如果 i==0 或 j==0,则 dp[i][j][0]=0, len[i][j][0]=0(空子数组)。
    否则,对于 r 从 0 到 k:
    • 相等情况:若 i>0 且 j>0 且 dp[i-1][j-1][r] ≠ INF,则 dp[i][j][r] = dp[i-1][j-1][r],len[i][j][r] = len[i-1][j-1][r]+1。
    • 不相等且 r>0:cost = abs(nums1[i-1]-nums2[j-1]),若 dp[i-1][j-1][r-1]+cost ≤ C 且 dp[i-1][j-1][r-1]≠INF,则更新 dp[i][j][r]=dp[i-1][j-1][r-1]+cost,len[i][j][r]=len[i-1][j-1][r-1]+1。
      注意:如果同时满足相等和不相等,取 len 更大的。
  4. 最终答案 = max{len[i][j][r]} 对所有 i,j,r 满足 r ≤ k 且 dp[i][j][r] ≤ C。

此算法时间复杂度 O(n1n2k),空间可通过滚动数组优化为 O(n2*k)。

最长重复子数组的变种:最多允许k次替换的最长公共子数组(进阶版:替换代价为权重,限制替换操作总代价不超过C) 题目描述 给定两个整数数组 nums1 和 nums2 ,以及一个非负整数 k 和一个正整数 C 。我们允许在匹配子数组时,最多进行 k 次“替换”操作,每次替换操作可以将 nums1 中某个位置的值改为任意整数(即与 nums2 中对应位置的值匹配),但每次替换操作有一个正整数代价(由给定的代价函数决定)。替换操作的总代价不能超过 C 。我们需要找到最长的公共子数组长度,使得在满足替换次数不超过 k 且替换总代价不超过 C 的条件下, nums1 的一个子数组与 nums2 的一个子数组完全相同。 注意 : 子数组必须是连续的。 替换操作只能用于 nums1 中的元素(或对称地用于 nums2 ,但题目通常约定修改一个数组)。 代价函数可以简化:假设代价为被替换元素的“改变量”的绝对值,即 abs(nums1[i] - newValue) ,但 newValue 必须等于 nums2[j] ,因此单次替换代价为 abs(nums1[i] - nums2[j]) 。 题目是经典“最多允许k次替换的最长重复子数组”的增强版,增加了代价限制,使得问题更接近实际匹配中的容错匹配。 解题步骤 这是一个二维动态规划问题,但状态需要额外记录替换次数和当前代价。为了降低复杂度,我们可以采用 滑动窗口 + 动态规划优化 或 三维DP 。下面我将详细解释三维DP解法,因为其思路更直观,便于理解状态转移。 定义状态 设 dp[i][j][c] 表示以 nums1[i-1] 和 nums2[j-1] 结尾的公共子数组,在使用了恰好 c 次替换操作时的最小替换代价。但这样定义会导致状态数过大(因为代价维度是C)。更好的方法是将“代价”视为资源限制,用状态记录替换次数,并在转移时检查代价是否允许。 我们定义状态为: dp[i][j][k_used] 表示以 nums1[i-1] 和 nums2[j-1] 结尾的公共子数组的长度,其中已经使用了 k_used 次替换操作,并且替换总代价不超过 C 的最大长度。但“长度”不适合直接做DP值,因为长度是我们要最大化的目标。我们可以转换思路:用 dp[i][j][k_used] 表示“以nums1[ i-1]和nums2[ j-1]结尾的公共子数组,在使用了k_ used次替换时的最小总代价”,然后在所有代价 ≤ C 的状态中找最长的子数组长度。 但这样依然复杂。更实用的方法是:用 二维DP + 第三维为替换次数 ,并在状态转移时累积代价,但代价累积后我们只关心是否 ≤ C。由于代价是累加的,我们可以在递推过程中计算代价,并只保留那些代价 ≤ C 的状态。 简化 :假设代价是每次替换固定的(比如每次替换代价=1),那么只需记录替换次数即可,原题是“最多允许k次替换的最长公共子数组”,经典解法是滑动窗口或DP。但这里代价可变,我们需要调整。 重新规划状态 设 dp[i][j][k_used] 表示以 nums1[i-1] 和 nums2[j-1] 结尾的公共子数组,在使用恰好 k_ used 次替换时的最小累计代价。如果无法形成这样的子数组,代价设为无穷大(INF)。 状态转移方程分两种情况: 如果 nums1[i-1] == nums2[j-1] ,则不需要替换: dp[i][j][k_used] = dp[i-1][j-1][k_used] (继承之前的代价) 但前提是 i>1 且 j>1 且 dp[i-1][j-1][k_used] != INF ,否则如果 i==1 或 j==1 ,则这是一个新的子数组起点,代价为0。 如果 nums1[i-1] != nums2[j-1] ,则可以选择替换(如果 k_ used > 0): 替换代价增加 abs(nums1[i-1] - nums2[j-1]) ,所以: dp[i][j][k_used] = dp[i-1][j-1][k_used-1] + cost 其中 cost = abs(nums1[i-1] - nums2[j-1]) 。 同样,如果 i==1 或 j==1 ,则之前代价为0。 初始条件:当 i=0 或 j=0 时,不存在以它结尾的子数组,我们可以不考虑这些状态,直接从 i=1,j=1 开始递推。但为了方便,我们可以将 dp[0][*][*] 和 dp[*][0][*] 设为 INF,除了 dp[0][0][0]=0 这种虚拟状态。不过通常我们初始化每个 (i,j) 时,如果 nums1[ i-1]==nums2[ j-1],则 dp[i][j][0]=0 ,否则 dp[i][j][1]=cost (如果k>=1)。 但这样定义 dp 值为代价,我们怎么得到最长长度? 我们需要另一个数组 len[i][j][k_used] 记录长度。但可以简化:因为 dp 值记录最小代价,只要 dp 值 ≤ C,就说明这个子数组可行,其长度就是当前连续匹配的长度,这个长度可以在递推时累积。 更好的方法:不记录代价在状态值里,而是将代价作为第四维,但那样状态太多。我们换个思路: 优化思路:二分答案 + 二维DP检查 我们可以二分查找最长长度 L,然后检查是否存在长度为 L 的公共子数组,使得替换次数 ≤ k 且替换总代价 ≤ C。 如何检查? 对于给定的长度 L,我们可以枚举所有起始位置 i 在 nums1,j 在 nums2,然后计算从 (i, j) 开始的长度为 L 的子数组的替换次数和总代价。但这样是 O(n1 n2 L) 的。 我们可以用 前缀和优化 : 先预处理 diff[i][j] = abs(nums1[i] - nums2[j]) ,然后对每个对齐位置偏移 p = i-j,在对应对齐的斜线上,用滑动窗口维护窗口内 diff 的和,找到窗口内 diff 的和 ≤ C 且窗口内非零 diff 的数量 ≤ k 的最大窗口长度。但这要枚举偏移 p,复杂度 O((n1+n2)* n1) 左右,稍复杂。 但更通用的检查方法是 DP : 定义 f[i][j] 表示以 nums1[ i] 和 nums2[ j ] 结尾的公共子数组,在替换代价 ≤ C 的前提下,最少替换次数。 但这里“替换次数最少”和“代价 ≤ C”是双重约束,我们可以反过来:在替换次数 ≤ k 下,最小化代价,看是否 ≤ C。 这可以通过二维DP,状态是 (i,j,used),used 是替换次数,值为最小代价,然后看 used ≤ k 中是否有代价 ≤ C 的。 不过二分长度 L 后,我们只需判断是否存在长度 ≥ L 的子数组,这可以通过计算每个 (i,j) 结尾的最长匹配(满足代价约束)是否 ≥ L 来判断。 最终采用的DP解法(三维DP,记录长度) 我们设 dp[i][j][c] 表示以 nums1[ i-1] 和 nums2[ j-1 ] 结尾的公共子数组,在替换总代价恰好为 c 时的最大长度(c 从 0 到 C)。 初始化:dp 全为 0。 转移方程: 如果 nums1[ i-1] == nums2[ j-1 ]: 对于每个 c 从 0 到 C: dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c] + 1) (如果 i>1 且 j>1),否则 dp[ i][ j][ c ]=1(当 i=1 或 j=1 时单独处理)。 如果 nums1[ i-1] != nums2[ j-1],设 cost = abs(nums1[ i-1] - nums2[ j-1 ]): 对于每个 c 从 cost 到 C: dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c-cost] + 1) (前提是 dp[ i-1][ j-1][ c-cost ] > 0 或 c==cost 且 i-1==0 或 j-1==0 时长度为1)。 注意:c 维度是代价,我们要让长度最大,所以 dp 值存储长度。 最后答案就是所有 i, j, c ≤ C 中 dp[ i][ j][ c ] 的最大值。 复杂度 :O(n1 * n2 * C),C 是代价上限,如果 C 很大,此法不可行。但在很多实际问题中 C 是较小的整数。 例子说明 设 nums1 = [ 1,3,5], nums2 = [ 3,1,5 ], k=1, C=2。 代价函数:cost = abs(nums1[ i]-nums2[ j ])。 我们尝试 dp 过程: 初始化 dp 全 0。 i=1, j=1: nums1[ 0]=1, nums2[ 0]=3, 不等,cost=2,c=2 时 dp[ 1][ 1][ 2 ]=1。 i=1, j=2: 1 和 1 相等,c=0 时 dp[ 1][ 2][ 0 ]=1。 i=1, j=3: 1 和 5 不等,cost=4>2,忽略(代价超)。 i=2, j=1: 3 和 3 相等,c=0 时 dp[ 2][ 1][ 0]=max(0, dp[ 1][ 0][ 0]+1),但 dp[ 1][ 0][ 0 ] 不存在,视为0,所以长度=1。 i=2, j=2: 3 和 1 不等,cost=2,c=2 时 dp[ 2][ 2][ 2]=max(0, dp[ 1][ 1][ 0]+1),但 dp[ 1][ 1][ 0 ]=0,所以长度=1。 i=2, j=3: 3 和 5 不等,cost=2,c=2 时 dp[ 2][ 3][ 2]=max(0, dp[ 1][ 2][ 0]+1),而 dp[ 1][ 2][ 0 ]=1,所以长度=2。 i=3, j=1: 5 和 3 不等,cost=2,c=2 时 dp[ 3][ 1][ 2]=max(0, dp[ 2][ 0][ 0 ]+1)=1。 i=3, j=2: 5 和 1 不等,cost=4>2,忽略。 i=3, j=3: 5 和 5 相等,c=0 时 dp[ 3][ 3][ 0]=dp[ 2][ 2][ 0]+1,但 dp[ 2][ 2][ 0 ]=0,所以长度=1。 最后检查所有 dp 值,最大长度是 dp[ 2][ 3][ 2]=2,即子数组 nums1[ 1..2]=[ 3,5] 与 nums2[ 2..3]=[ 1,5] 在替换 nums1[ 1 ] 从3改为1(代价2)后相同。 但这里替换次数是1(k=1满足),代价=2(C=2满足),所以答案是2。 总结步骤 确定代价计算方式(本题为绝对值差)。 定义三维数组 dp[ i][ j][ c] 表示以 nums1[ i-1] 和 nums2[ j-1 ] 结尾的公共子数组,在总替换代价为 c 时的最大长度。 初始化 dp 为0。 遍历 i 从 1 到 n1,j 从 1 到 n2: 如果两数相等,则对每个 c 从 0 到 C:若 dp[ i-1][ j-1][ c] 有值,则 dp[ i][ j][ c] = dp[ i-1][ j-1][ c]+1;否则若 i=1 或 j=1,则 dp[ i][ j][ c ]=1。 如果两数不等,计算 cost,对每个 c 从 cost 到 C:若 dp[ i-1][ j-1][ c-cost] 有值,则 dp[ i][ j][ c] = max(dp[ i][ j][ c], dp[ i-1][ j-1][ c-cost]+1);否则若 i=1 或 j=1 且 c==cost,则 dp[ i][ j][ c ]=1。 最终答案为所有 dp[ i][ j][ c ] 的最大值,且满足替换次数 ≤ k 吗?等等,我们还没记录替换次数! 问题:我们只记录了总代价,没记录替换次数。所以需增加一维记录替换次数,变为四维 dp[ i][ j][ c][ r ]:代价 c,替换次数 r 时的最大长度,但这样状态太大。 调整 :既然替换次数 ≤ k 且代价 ≤ C,我们可以将代价视为“资源”,记录最少替换次数达到某个代价的状态,但更直接的方法是: 用 dp[ i][ j][ r] 表示以 nums1[ i-1] 和 nums2[ j-1 ] 结尾的公共子数组,在替换次数为 r 时的最小总代价。 然后如果 dp[ i][ j][ r] ≤ C,则其对应的长度可以由另一个数组 len[ i][ j][ r ] 记录。 转移: 若 nums1[ i-1]==nums2[ j-1],则 dp[ i][ j][ r] = dp[ i-1][ j-1][ r],len=len[ i-1][ j-1][ r ]+1。 若不相等,则 dp[ i][ j][ r] = dp[ i-1][ j-1][ r-1] + cost,len=len[ i-1][ j-1][ r-1 ]+1(若 r>0)。 初始化:dp[ 0][ ][ ]=INF,dp[ ][ 0][ ]=INF,dp[ 0][ 0][ 0]=0,len[ 0][ 0][ 0 ]=0。 最后,找出所有 r ≤ k 且 dp[ i][ j][ r] ≤ C 的 len[ i][ j][ r ] 的最大值。 复杂度 O(n1 n2 k),可行。 最终算法 初始化 dp[ n1+1][ n2+1][ k+1] 为无穷大,len[ n1+1][ n2+1][ k+1 ]=0。 dp[ 0][ 0][ 0]=0, len[ 0][ 0][ 0 ]=0。 遍历 i 从 0 到 n1,j 从 0 到 n2(i,j 不同时为0): 如果 i==0 或 j==0,则 dp[ i][ j][ 0]=0, len[ i][ j][ 0 ]=0(空子数组)。 否则,对于 r 从 0 到 k: 相等情况:若 i>0 且 j>0 且 dp[ i-1][ j-1][ r] ≠ INF,则 dp[ i][ j][ r] = dp[ i-1][ j-1][ r],len[ i][ j][ r] = len[ i-1][ j-1][ r ]+1。 不相等且 r>0:cost = abs(nums1[ i-1]-nums2[ j-1]),若 dp[ i-1][ j-1][ r-1]+cost ≤ C 且 dp[ i-1][ j-1][ r-1]≠INF,则更新 dp[ i][ j][ r]=dp[ i-1][ j-1][ r-1]+cost,len[ i][ j][ r]=len[ i-1][ j-1][ r-1 ]+1。 注意:如果同时满足相等和不相等,取 len 更大的。 最终答案 = max{len[ i][ j][ r]} 对所有 i,j,r 满足 r ≤ k 且 dp[ i][ j][ r ] ≤ C。 此算法时间复杂度 O(n1 n2 k),空间可通过滚动数组优化为 O(n2* k)。