最长重复子数组的变种:允许最多k次元素替换的最长公共子数组
字数 1069 2025-11-08 10:02:38
最长重复子数组的变种:允许最多k次元素替换的最长公共子数组
题目描述
给定两个整数数组nums1和nums2,以及一个整数k。我们需要找到最长的公共子数组的长度,该子数组在nums1和nums2中出现,且允许在匹配过程中最多进行k次元素替换。这里的"替换"指的是如果nums1[i] ≠ nums2[j],我们可以将其视为匹配,但计入替换次数。
示例
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7], k = 1
输出:3
解释:最长公共子数组是[3,2,1]或[2,3,1](替换1次)
解题过程
1. 问题分析
这是最长重复子数组问题的变种,增加了最多k次替换的灵活性。我们需要找到两个数组中的连续子数组,使得它们相似度最高(最多k个位置不同)。
2. 动态规划定义
定义dp[i][j][t]表示以nums1的第i个元素和nums2的第j个元素结尾的子数组,在使用恰好t次替换时的最大公共子数组长度。
3. 状态转移方程
- 如果nums1[i-1] == nums2[j-1](匹配成功):
dp[i][j][t] = dp[i-1][j-1][t] + 1 - 如果nums1[i-1] != nums2[j-1](需要替换):
当t > 0时,dp[i][j][t] = dp[i-1][j-1][t-1] + 1
当t = 0时,dp[i][j][0] = 0(不能替换) - 边界情况:当i=0或j=0时,dp[i][j][t] = 0
4. 初始化
- 创建三维数组dp[len1+1][len2+1][k+1]
- 所有元素初始化为0
5. 填充DP表
我们按顺序遍历所有可能的状态:
for i in range(1, len1+1):
for j in range(1, len2+1):
for t in range(k+1): # t从0到k
if nums1[i-1] == nums2[j-1]:
dp[i][j][t] = dp[i-1][j-1][t] + 1
else:
if t > 0:
dp[i][j][t] = dp[i-1][j-1][t-1] + 1
else:
dp[i][j][t] = 0
6. 寻找最大值
我们需要在所有可能的替换次数(0到k)中找到最大值:
max_length = 0
for i in range(len1+1):
for j in range(len2+1):
for t in range(k+1):
max_length = max(max_length, dp[i][j][t])
7. 空间优化
由于dp[i][j][t]只依赖于dp[i-1][j-1][t]和dp[i-1][j-1][t-1],我们可以使用二维数组进行空间优化:
# 使用两个二维数组交替计算
dp_prev = [[0]*(k+1) for _ in range(len2+1)]
dp_curr = [[0]*(k+1) for _ in range(len2+1)]
max_length = 0
for i in range(1, len1+1):
for j in range(1, len2+1):
for t in range(k+1):
if nums1[i-1] == nums2[j-1]:
dp_curr[j][t] = dp_prev[j-1][t] + 1
else:
if t > 0:
dp_curr[j][t] = dp_prev[j-1][t-1] + 1
else:
dp_curr[j][t] = 0
max_length = max(max_length, dp_curr[j][t])
dp_prev, dp_curr = dp_curr, dp_prev # 交换数组
8. 时间复杂度分析
- 时间复杂度:O(len1 × len2 × k)
- 空间复杂度:O(len2 × k)(优化后)
关键理解点
- 替换操作允许我们在元素不匹配时仍然可以延长公共子数组
- 替换次数t是累积的,需要记录在不同替换次数下的最优解
- 最终结果是所有可能替换次数下的最大值
这种方法通过动态规划巧妙地处理了替换操作,在保持算法效率的同时解决了复杂的匹配问题。