最短编辑距离题解(区间dp)

原题链接

题目描述

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

  1. 删除–将字符串 A A A 中的某个字符删除。
  2. 插入–在字符串 A A A 的某个位置插入某个字符。
  3. 替换–将字符串 A A A 中的某个字符替换为另一个字符。

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

输入格式

第一行包含整数 n n n,表示字符串 A A A 的长度。

第二行包含一个长度为 n n n 的字符串 A A A

第三行包含整数 m m m,表示字符串 B B B 的长度。

第四行包含一个长度为 m m m 的字符串 B B B

字符串中均只包含大小写字母。

输出格式

输出一个整数,表示最少操作次数。

数据范围

1 ≤ n , m ≤ 1000 1 \le n, m \le 1000 1n,m1000

输入样例:
10 
AGTCTGACGC
11 
AGTAAGTAGGC
输出样例:
4

算法

(线性 d p dp dp) O ( n m ) O(nm) O(nm)

本题比较难想的就是如何去表示我们的动态规划状态,根据以往的经验,很多动态规划的题目基本都是考虑我们最后一步或者倒数第二部的状态。本题可以考虑把 a a a数组的前 i i i个字母与 b b b数组的前 j j j的字母进行匹配作为状态定义。

如何转移呢?我们可以从题目条件出发,题目给出了增删改 3 3 3种操作,我们通过这 3 3 3种方式将 a a a的前 i i i个字母与 b b b的前 j j j个字母匹配:

  1. 通过在 a a a的第 i i i个元素后面增加一个元素使得当前的 a a a b b b匹配,即 f [ i ] [ j ] = f [ i ] [ j − 1 ] + 1 f[i][j] = f[i][j - 1] + 1 f[i][j]=f[i][j1]+1
  2. 通过删除 a a a的第 i i i个元素使得 a a a b b b匹配。即 f [ i ] [ j ] = f [ i − 1 ] [ j ] + 1 f[i][j] = f[i - 1][j] + 1 f[i][j]=f[i1][j]+1
  3. 通过修改 a a a的第 i i i个元素使得 a a a b b b匹配。即 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + 1 f[i][j] = f[i - 1][j - 1] + 1 f[i][j]=f[i1][j1]+1
  4. 如果 a [ i ] a[i] a[i]本身等于 b [ j ] b[j] b[j],则对当前这次不操作。即 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] f[i][j] = f[i - 1][j - 1] f[i][j]=f[i1][j1]

在这里插入图片描述

初始化: 通过上述的状态转移方程可以看出,我们的f[i][j]可能会涉及到0这个下标,所以就需要对 f f f进行初始化(许多时候考虑是否要初始化的一个重要依据)。考虑下 f f f第一维为0代表的含义:让 a a a的前 0 0 0个字母和 b b b的前 i i i个字母进行匹配,只有一种最优方法, b b b有多长我们就需要对 a a a增加多少个元素让两者匹配,即 f [ 0 ] [ i ] = i f[0][i] = i f[0][i]=i;再考虑 f f f第二维为0代表的含义:让 a a a的前 i i i个字母与 b b b的前 0 0 0个字母匹配,也只有一种最优方法, a a a有多长就删掉多少个元素,即 f [ i ] [ 0 ] = i f[i][0] = i f[i][0]=i

时间复杂度

两重循环,时间复杂度 O ( n m ) O(nm) O(nm)

J a v a Java Java 代码
import java.util.*;

public class Main {
	static final int N = 1010;
	static int[][] f = new int[N][N];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		//读入数据
		int n = sc.nextInt();
		char[] a = (" " + sc.next()).toCharArray(); //让其下标从1开始
		int m = sc.nextInt();
		char[] b = (" " + sc.next()).toCharArray();
		
		//初始化
		for (int i = 0; i <= n; i ++) f[i][0] = i; 
		for (int i = 0; i <= m; i ++) f[0][i] = i;
		
		//动态规划
		for (int i = 1; i <= n; i ++) {
			for (int j = 1; j <= m; j ++) {
				f[i][j] = Math.min(f[i][j - 1] + 1, f[i - 1][j] + 1);
				if (a[i] != b[j]) f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1);
				else f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]);
			}
		}
		
		//输出答案
		System.out.print(f[n][m]);
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辞寒oo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值