动态规划求解-将字符串A变换为字符串B 所用的最少字符操作次数

问题描述:
设A 和B 是2 个字符串。要用最少的字符操作将字符串A 转换为字符串B。
这里所说的字符操作包括
(1)删除一个字符;
(2)插入一个字符;
(3)将一个字符改为另一个字符。
将字符串A变换为字符串B 所用的最少字符操作次数也称为字符串A到B 的编辑距离,记为 d(A,B)。
试设计一个有效算法,对任给的2 个字符串A和B,计算出它们的编辑距离d(A,B)。
在这里插入图片描述
这里抄袭了一位大佬的利用二维数组求解的思路图,做的挺好,他的算法结果也是对的,就给大家摘抄下来了。图片的原博客链接是:https://blog.csdn.net/ma2413419/article/details/82693319#commentsedit。
而很多其他大佬的对于本题求解的算法,其实是有毛病的,就是没考虑到两个字符串第一个元素是否相等的问题,这样的结果会对后面的造成影响。这就叫做一步错,步步错。
好啦,接下来就开始一起看思路与代码吧!
根据变化编辑距离的变化规律,不难得出如下的结论:

 d[i][j]=min(min(d[i-1][j]+1,d[i][j-1]+1),(a[j-1]==b[i-1]?d[i-1][j-1]:d[i-1][j-1]+1));

下面我讲解三种求解该问题的方法:

一、(1)利用二维静态数组求法(c++版):
顾名思义,就是构造数组取存储每一个对应的字符串a的前i个元素与字符串b的前j个元素的最小编辑距离d[i][j].

#include<iostream>
#include<string>
int GetMinEditDistance(std::string a,std::string b);
int main()//这种方法有一个不足就是不能返回多个值。如果以指针形式返回,那么就可以得出想要的结果。 
{
	std::string a,b;
	std::cin>>a>>b;
	GetMinEditDistance(a,b);
    std::cout<<GetMinEditDistance(a,b);
	return 0;
 } 
 int GetMinEditDistance(std::string a,std::string b)
 {
 	int length_a=a.length();
 	int length_b=b.length();
 	int d[length_b+1][length_a+1]={0};
 	
	 for(int i=1;i<=length_a;i++)
	 {
	 	d[0][i]=i;    //把第一行行值确定
	 }
 	for(int i=1;i<=length_b;i++)
	 {
	 	d[i][0]=i;    //把第一列列值确定
	 }
 	for(int i=1;i<=length_b;i++)
 	{
 		for(int j=1;j<=length_a;j++)
 		{
 			d[i][j]=std::min(std::min(d[i][j-1]+1,d[i-1][j]+1),a[j-1]==b[i-1]?d[i-1][j-1]:d[i-1][j-1]+1);     //动态求解三种方式下的字符串a的前i个元素与字符串b的前j个元素的最小编辑距离
		 }
	 }
	return d[length_b][length_a];  //返回最小编辑距离数值
 }
 

(2)利用二维静态数组求法(C语言版):

#include<stdio.h>
#include<cstring>
int editdistance(char a[],int length_a,char b[],int length_b);
 int GetMinNum(int a, int b, int c);
int main()
{
	char a[100];
	char b[100];
	gets(a);
	gets(b);
	int length_a=strlen(a);
	int length_b=strlen(b);
	int c=editdistance(a,length_a,b,length_b);
	
	printf("%d",c);
	return 0;
 } 
 int GetMinNum(int a, int b, int c)//获取三个数中最小数
{
    int min = a < b ? a : b;
    return min < c ? min : c;
}
 
 int editdistance(char a[],int length_a,char b[],int length_b)
 {
 	int d[length_b+1][length_a+1]={0};
 	for(int i=1;i<=length_a;i++)
 	{
 		d[0][i]=i;
	 }
 	for(int i=1;i<=length_b;i++)
 	{
 		d[i][0]=i;
	 }
 	for(int i=1;i<=length_b;i++)
 	{
 		for(int j=1;j<=length_a;j++)
 		d[i][j]=GetMinNum(d[i][j-1]+1,d[i-1][j]+1,b[i-1]==a[j-1]?d[i-1][j-1]:d[i-1][j-1]+1);
	 }
	 return d[length_b][length_a];
 }

二、利用指针法求解(C++版)
要定义指针变量求解的话,必须要首先分配内存空间,让指针指向这一部分内存空间。
对于同一本题,我们需要定义一个指向指针(假设定义为 int *a)的指针变量(那么这个指针变量就可以定义为int * *a)。利用指针法求解的好处是可以通过在定义的函数中返回一个指针值,通过返回到主函数的这个指针值,可以把整个二维数组打印出来。

(1)利用int *p=new int[n]分配内存空间方法求解问题的代码如下:

#include<iostream>
#include<cstring>
int** MinEditDistance(std::string a,int length_a,std::string b,int length_b);
int main()
{
	std::string a,b;
	std::cin>>a>>b;
	int length_a=a.length();
 	int length_b=b.length();
	int** p=MinEditDistance(a,length_a,b,length_b);
		for(int i=1;i<=length_b;i++)
 	{
 		for(int j=1;j<=length_a;j++)
    	std::cout<<p[i][j]<<" ";
        std::cout<<std::endl;
	}
	return 0;
 } 
 int** MinEditDistance(std::string a,int length_a,std::string b,int length_b)
 {
 	int **d=new int*[length_b+1];
 	for(int i=0;i<=length_b;i++)
 	{
 		d[i]=new int[length_a+1];
	 }
 	d[0][0]=0;
 	for(int i=1;i<=length_a;i++)
 	{
 		d[0][i]=i;
	 }
 	for(int i=1;i<=length_b;i++)
 	{
 		d[i][0]=i;
	 }
 	for(int i=1;i<=length_b;i++)
 	{
 		for(int j=1;j<=length_a;j++)
 		d[i][j]=std::min(std::min(d[i][j-1]+1,d[i-1][j]+1),a[j-1]==b[i-1]?d[i-1][j-1]:d[i-1][j-1]+1);
	 }
	 return d;
 }

(2)利用int *p=(int *)molloc(sizeof(int))分配内存空间方法求解问题的代码如下:

#include<iostream>
#include<string>
#include<stdlib.h>
 int **EditDistance(std::string a,int length_a,std::string b,int length_b);
 int main()
 {
    std::string a,b;
 	std::cin>>a>>b;
 	int length_a=a.length();
 	int length_b=b.length();
 	int **p=EditDistance(a,length_a,b,length_b);
 	for(int i=1;i<=length_b;i++)
 	{
 		for(int j=1;j<=length_a;j++)
 		std::cout<<p[i][j]<<" ";
 		std::cout<<std::endl;
	 }
	 std::cout<<"min="<<p[length_b][length_a];
 	return 0;
  } 
  int **EditDistance(std::string a,int length_a,std::string b,int length_b)
  {
  	int **d=(int **)malloc(length_b*sizeof(int*));
  	for(int i=0;i<=length_b;i++)
  	{
  		d[i]=(int *)malloc(length_a*sizeof(int));
	  }
	  d[0][0]=0;
  	for(int i=1;i<=length_a;i++)
  	{
  		d[0][i]=i;
	  }
	 for(int i=1;i<=length_b;i++)
	  {
	  	d[i][0]=i;
	  }
	  for(int i=1;i<=length_b;i++)
	  {
	  	for(int j=1;j<=length_a;j++)
	  	{
	  		d[i][j]=std::min(std::min(d[i][j-1]+1,d[i-1][j]+1),a[j-1]==b[i-1]?d[i-1][j-1]:d[i-1][j-1]+1);
		  }
	  }
	  return d;
  }

好啦,大概就是这些了,如果再想到啥好的算法,还会和继续和大家分享的,咱们一起讨论,一起进步,希望学习C++/C的广大码农们,一定要坚持哦,加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值