题目:
给定两个字符串 A 和 B,现在要将 A 经过若干操作变为 B,可进行的操作有:

  • 删除–将字符串 A 中的某个字符删除
  • 插入–在字符串 A 的某个位置插入某个字符
  • 替换–将字符串 A 中的某个字符替换为另一个字符

现在请你求出,将 A 变为 B 至少需要进行多少次操作

第一行包含整数 n,表示字符串 A 的长度
第二行包含一个长度为 n 的字符串 A
第三行包含整数 m,表示字符串 B 的长度
第四行包含一个长度为 m 的字符串 B
(字符串中均只包含大小写字母)

输出一个整数,表示最少操作次数
1 ≤ n, m ≤ 1000

输入:
10
AGTCTGACGC
11
AGTAAGTAGGC
输出:
4
public class 线性dp_最短编辑距离 {
    public static int N = 1010, n, m;
    public static char[] a = new char[N], b = new char[N];
    public static int[][] f = new int[N][N];

    public static void main(String[] args) {
        //读入,一般情况下dp问题是从1开始比较好
        Scanner in = new Scanner(System.in);
        n = in.nextInt(); String A = in.next();
        m = in.nextInt(); String B = in.next();
        for (int i = 1; i<=n; i++) a[i] = A.charAt(i-1);
        for (int i = 1; i<=m; i++) b[i] = B.charAt(i-1);

        //先将所有的0进行初始化(因为后续计算中涉及到i-1和j-1,所以必须将0代表的东西表示出来)
        for (int i = 0; i<=m; i++) f[0][i] = i;  //当a中的前0个字符想和b中的前i个字符匹配的话,只能是进行添加i个字符
        for (int i = 0; i<=n; i++) f[i][0] = i;  //当a中的前i个字符想和b中的前0个字符匹配的话,只能是进行删除i个字符

        //状态计算
        for (int i = 1; i<=n; i++) {
            for (int j = 1; j<=m; j++) {
                //计算部分的分析见文中
                f[i][j] = Math.min(f[i-1][j], f[i][j-1]) + 1;
                if (a[i] == b[j]) f[i][j] = Math.min(f[i][j], f[i-1][j-1]);
                else f[i][j] = Math.min(f[i][j], f[i-1][j-1] + 1);
            }
        }

        //最后输出结果
        System.out.println(f[n][m]);
    }
}

思路:
经典y式dp法

1.状态表示
f[i][j] :使(A的前 i 个字符)变为(B的前 j 个字符)的最少编辑次数(每次删,增,改皆记为编辑一次)

2.状态计算(状态转移)
分为三种情况来看:
1.删除:A的前 i 位删除 i 后,和B的前 j 位相同,说明A的前 i-1 和B的前 j 相同,删除第 i 位算作一次编辑,最后得到 f[i-1][j] + 1
2.增加:A的前 i 位增加一位,和B的前 j 位相同,说明A的前 i 位和B的前 j-1相同,增加算作一次编辑,最后得到 f[i][j-1] + 1
3.替换:
如果当前A[i] 和 B[j] 相同,那么就直接将 f[i-1][j-1] 转移过来即可
如果不相同的话,那么将A[i] 改为 B[j], 也就是 f[i-1][j-1] + 1,更改算作一次编辑