leetcode-动态规划三种问题的异同点

一、问题定义

|---------|-------------|---------------------------------|
| 问题 | 输入 | 输出 |
| 最长重复子数组 | 两个数组/字符串A,B | 最长的连续子数组,同时出现在A和B中 |
| 最长公共子序列 | 两个序列A,B | 最长的子序列(元素相对顺序一致,可不连续),同时出现在A和B中 |
| 编辑距离 | 两个字符串A,B | 将A转换成B所需的最少插入,删除,替换操作次数 |

二、动态规划解法对比

1.状态定义

  • 重复子数组:dp[i][j]表示以A[i-1]和B[j-1]结尾的最长公共子串的长度
  • 公共子序列:dp[i][j]表示A[0..i-1]和B[0..j-1]的最长公共子序列的长度
  • 编辑距离:dp[i][j]表示将A[0..i-1] 转换成 B[0..j-1]所需的最少操作次数

2.状态转移方程

设m= len(A),n = len(B),下标从1开始(即dp[i][j] 对应A[i-1]与B[j-1])

|-------|-------------------------------------|---------------------------------------------------------------------|
| 问题 | 当A[i-1]==B[j-1] | 当A[i-1]!=B[j-1] |
| 重复子数组 | dp[i][j]=dp[i-1][i-1]+1 | dp[i][j]=0(连续中断) |
| 公共子序列 | dp[i][j]=dp[i-1][j-1]+1 | dp[i][j]=max(dp[i-1][j],dp[i][j-1]) |
| 编辑距离 | dp[i][j]=dp[i-1][j-1](无需操作) | dp[i][j]=min(dp[i-1][j], dp[i][j-1],dp[i-1][j-1])+1 |

3.初始化

  • 重复子数组:dp[0][j]=0,dp[i][0]=0(空串匹配长度为0)
  • 公共子序列:同上,全0
  • 编辑距离:dp[i][0]=i (将A前i个字符删除),dp[0][j]=j(插入j个字符)

4.最终答案

  • 重复子数组:max(dp[i][j]) ,即DP表中最大值(因为最佳子串不一定在末尾结束)
  • 公共子序列:dp[m][n]
  • 编辑距离:dp[m][n]

三、异同点

相同点

  1. 动态规划框架:都基于二维表,逐行逐列递推
  2. 时间复杂度:均为O(mn),空间均可优化到O(min(m,n))
  3. 子结构:都利用了"前缀"的最优解来构造更长前缀的最优解

不同点

维度 重复子数组 公共子序列 编辑距离
连续性要求 必须连续 不要求连续 不直接涉及连续,但通过操作调整
不等时的行为 置 0(重新开始) 取左/上的最大值(跳过) 取三种操作的最小值+1
初始化 全 0 全 0 第一行、第一列为 i, j
最终答案 全局最大值 右下角 右下角
DP 值的含义 以当前位置结尾的最长匹配长度 前缀的最长公共子序列长度 前缀的最小编辑代价
空间优化难度 简单(仅需上一行) 中等(需两行) 中等(需两行,并保存左上角)

四、举例说明

设 A = "abcde", B = "abfce"

1. 最长重复子数组(公共子串)

  • 匹配的连续段:"ab"(长度 2)、"c"(长度 1)、"e"(长度 1)。

  • DP 表(只写部分):

    text

    复制

    下载

    复制代码
         a  b  f  c  e
    a    1  0  0  0  0
    b    0  2  0  0  0
    c    0  0  0  1  0
    d    0  0  0  0  0
    e    0  0  0  0  1

    最大值 = 2 → "ab"

2. 最长公共子序列

  • 子序列:"abce"(长度 4)。

  • DP 表(右下角):

    text

    复制

    下载

    复制代码
         a  b  f  c  e
    a    1  1  1  1  1
    b    1  2  2  2  2
    c    1  2  2  3  3
    d    1  2  2  3  3
    e    1  2  2  3  4

    答案 = 4。

3. 编辑距离("abcde""abfce"

  • 最少操作:将 'c' 替换为 'f',然后删除 'd'?实际最优:把 'c' 改成 'f'(1 次),再把 'd' 删除(1 次),共 2 次。

  • DP 表右下角 = 2。

五、代码示例

1.最长重复子数组

python 复制代码
def findLength(A, B):
    m, n = len(A), len(B)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    ans = 0
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if A[i-1] == B[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
                ans = max(ans, dp[i][j])
    return ans

2.最长公共子序列

python 复制代码
def longestCommonSubsequence(A, B):
    m, n = len(A), len(B)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if A[i-1] == B[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]

3.编辑距离

python 复制代码
def minDistance(A, B):
    m, n = len(A), len(B)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    for i in range(1, m + 1):
        dp[i][0] = i
    for j in range(1, n + 1):
        dp[0][j] = j
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if A[i-1] == B[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
    return dp[m][n]
相关推荐
迷你可可小生2 小时前
二叉树知识点
python·算法
Z1Jxxx2 小时前
C++ P1151 子数整数
开发语言·c++·算法
foundbug9992 小时前
基于种群分解与主元分析的NSGA-II优化算法
算法
计算机安禾2 小时前
【数据结构与算法】第37篇:图论(一):图的存储结构(邻接矩阵与邻接表)
数据结构·算法·链表·排序算法·深度优先·图论·visual studio code
sparEE2 小时前
基础排序算法:冒泡、选择、插入、希尔
数据结构·算法·排序算法
ths5122 小时前
测试开发python中正则表达式使用总结(二)
开发语言·python·算法
不爱吃炸鸡柳2 小时前
5道经典贪心算法题详解:从入门到进阶
开发语言·数据结构·c++·算法·贪心算法
枫叶林FYL2 小时前
【自然语言处理 NLP】8.3 长文本推理评估与针在大海堆任务
人工智能·算法