动态规划-编辑距离问题

问题描述:

输入一个字符串如:ABACBDAD,经过若干操作后变为:BDCABA

问题描述:设s和t是两个字符串,要用最少的字符操作将字符串s转换为字符串t,这里所说的字符操作包括

(1):删除一个字符;

(2):插入一个字符;

(3):修改一个字符。

将s转换为t所用的最少字符操作数称为s到t的编辑距离

问题分析:

设字符串s,t的长度分别是m、n,用字符S、T来存放

设置一个动态规划二维数组D,D[i][j]表示S与T的最优编辑距离(即S转换为T的最少操作步数)

显然,当t串空的时候要删除s中的全部字符转换为t,即D[i][0]=i;(删除s中的i个字符,共i次操作)。同理,当s串空时在s中插入t中的全部字符转换为t,即D[0][j]=j;(向s中插入t的j个字符,共j次操作)

对于非空的情况,当S[i-1]=T[j-1]时,这两个字符不需要任何操作,即D[i][j]=D[i-1][j-1]+0;当S[i-1]!=T[j-1]时,有3中操作可以达到目的

  • 将S[i-1]替换为T[j-1],即D[i][j]=D[i-1][j-1]+1(一次替换操作的次数为1)

② 在S[i-1]字符后插入T[j-1]字符,即D[i][j]=D[i][j-1]+1(一次插入操作的次数为1)

  • 删除S[i-1]字符,即D[i][j]=D[i-1][j]+1(一次删除操作的次数为1)

此时D[i][j]取3中操作的最小值,转换方程为:

 实验代码:

import java.util.Scanner;

public class Minimum_Edit_Distance {
	/**
	 * 
	 * @Description 找出a,b,c三者的最小值
	 * @author chen
	 * @datem 2021年11月3日下午3:17:29
	 * @param a
	 * @param b
	 * @param c
	 * @return minNumber最小值
	 */
	public static int minNumber(int a, int b, int c) {
		int temp = (a > b) ? b : a;
		int mintemp = (temp > c) ? c : temp;
		return mintemp;
	}

	/**
	 * @Description 距离步数和方式
	 * @author chen
	 * @datem 2021年11月3日下午3:18:43
	 * @param D   距离操作的步数的数组
	 * @param Rec 记录操作的方式(插入、删除、替换)的数组
	 * @param s
	 * @param t
	 */
	public static void Minimum_Edit_Distance(int D[][], String Rec[][], String s, String t) {
		char S[] = s.toCharArray();
		char T[] = t.toCharArray();
		int n = S.length;// 7
		int m = T.length;
		// 初始化
		D[0][0] = 0;
		for (int i = 1; i <= n; i++) {
			D[i][0] = i;
			Rec[i][0] = "U";
		}
		// 初始化
		Rec[0][0] = "0";
		for (int j = 1; j <= m; j++) {
			D[0][j] = j;
			Rec[0][j] = "L";

		}
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
//				替换/无需操作
				int c = 0;
				if (S[i - 1] != T[j - 1]) {
					c = 1;
				}
				int replace = D[i - 1][j - 1] + c;// 替换
				int delete = D[i - 1][j] + 1;// 删除
				int insert = D[i][j - 1] + 1;// 插入
				int min = minNumber(replace, delete, insert);

				if (replace == min) {// 替换
					D[i][j] = D[i - 1][j - 1] + c;
					Rec[i][j] = "LU";
				} else if (insert == min) {// 插入
					D[i][j] = D[i][j - 1] + 1;
					Rec[i][j] = "L";
				} else if (delete == min) {// 删除
					D[i][j] = D[i - 1][j] + 1;
					Rec[i][j] = "U";
				}

			}
		}
	}

	/**
	 * 
	 * @Description 输出操作方式
	 * @author chen
	 * @datem 2021年11月3日下午4:43:27
	 * @param Rec 记录操作的方式(插入、删除、替换)的数组
	 * @param s
	 * @param t
	 * @param i
	 * @param j
	 */
	public static void Print_MED(String Rec[][], String s, String t, int i, int j) {
		char S[] = s.toCharArray();
		char T[] = t.toCharArray();
		if (i == 0 && j == 0) {
			return;
		}

		// 替换/无需操作
		if (Rec[i][j] == "LU") {
			Print_MED(Rec, s, t, i - 1, j - 1);
			if (S[i - 1] == T[j - 1]) {
				System.out.println("无需操作");
			} else {
				System.out.println("用" + T[j - 1] + "替换" + S[i - 1] + ",");
			}
		} else if (Rec[i][j] == "U") {// 删除
			Print_MED(Rec, s, t, i - 1, j);
			System.out.println("删除" + S[i - 1]);
		} else if (Rec[i][j] == "L") {// 插入
			Print_MED(Rec, s, t, i, j - 1);
			System.out.println("插入" + T[j - 1]);
		}

	}

	/**
	 * 
	 * @Description 遍历String数组
	 * @author chen
	 * @datem 2021年11月3日下午3:56:36
	 * @param Rec
	 */
	public static void PrintArray(String Rec[][]) {
		int count = 0;
		for (int i = 0; i < Rec.length; i++) {
			for (int j = 0; j < Rec[i].length; j++) {
				System.out.print(Rec[i][j] + " ");
				count++;
				if (count % Rec[i].length == 0) {
					System.out.println();
				}
			}
		}
	}

	/**
	 * 
	 * @Description 遍历int数组
	 * @author chen
	 * @datem 2021年11月3日下午3:56:12
	 * @param D
	 */
	public static void PrintArray(int D[][]) {
		int count = 0;
		for (int i = 0; i < D.length; i++) {
			for (int j = 0; j < D[i].length; j++) {
				System.out.print(D[i][j] + " ");
				count++;
				if (count % D[i].length == 0) {
					System.out.println();
				}
			}
		}
	}

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		System.out.println("请输入第一个字符串:");
		String s = scan.next();
		System.out.println("请输入第二个字符串:");
		String t = scan.next();
		// 记录编辑距离
		int D[][] = new int[s.length() + 1][t.length() + 1];
		// 记录编辑方式
		String Rec[][] = new String[s.length() + 1][t.length() + 1];

		Minimum_Edit_Distance(D, Rec, s, t);
		Print_MED(Rec, s, t, s.length(), t.length());

		System.out.println("最短编辑距离为" + D[s.length()][t.length()]);

	}

}

实验结果:

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

平胸瑶女神

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

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

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

打赏作者

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

抵扣说明:

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

余额充值