【算法】【动态规划】字符串编辑距离问题

题目大意:

        就是给出两个字符串,只能进行增删改操作,问从字符串1转化为字符串2最少需要几步

状态转移方程

dp[i][j]        i和j分别表示两个字符串的长度

         当s1[i]==s2[j]的时候,说明不用操作,相当于当s1长度为i的时候和s2长度为j的时候不需要进行操作,所以次数和s1长度为i-1和s2长度为j-1的时候相等

        所以dp[i][j]=dp[i-1][j-1]

        当s1[i]!=s2[j]的时候,说明需要进行一步操作,具体是增删改里面的哪一步,根据下文可以理解

模拟过程

首先需要根据dp数组来进行判断,举下边这个例子

 s2\s1sfdqxbw
01234567
g1       
f2       
d3       
g4       
w5       

        首先先对dp数组进行初始化,先将两个数组的第一个元素s[0]插入一个空以便后面运算

        我们就比较容易知道当两个字符串都为空的时候,说明两个字符串相等,进行0步操作就可以完成相等的目的,所以dp[0][0]=0

        随后的数据按横行来举例,当值取到s的时候,相当于s1的值是s(本来是没有,现在有了一个元素),所以s2(此时为空)需要变成s1的s,需要进行一步添加操作来变成和s1一样,所以进行一步操作,所以dp[1][0]=1;

 同理当s1取到  sf  的时候s2需要进行两步添加操作,所以dp[2][0]=2

        同样的可以列举所有横行和竖行来进行初始化

当s1[i]!=s2[j]时,有dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1; 

        初始化完毕后需要进行循环遍历了,因为一开始在字符串s[0]的位置插入了了一个空,所以遍历需要在i=1和j=1进行遍历,当s1[i]!=s2[j]的情况中,说明肯定需要一步操作,dp[i][j]需要在

                s1的长度为i-1,s2的长度为j的情况,对应dp[i-1][j]

                s1的长度为i,s2的长度为j-1的情况,对应dp[i][j-1]

                s1的长度为i-1,s2的长度为j-1的情况,对应dp[i-1][j-1]

        三种情况中选择最小的来进行一步操作,三种情况分别代表的含义还是需要回到表格中寻找答案(这个解释自己看的也比较迷惑,不确定自己想的对不对)

具体是增加还是删除看这篇博客可能会好一点

详解编辑距离算法-Levenshtein Distance_BoCong-Deng的博客-优快云博客_编辑距离算法原理

        首先是dp[i-1][j]

        相当于s1的前i-1位和s2的前j-1位通过dp[i-1][j-1]已经相等了,但是j比i长了一位,所以让i加一位变成dp[i][j],i做了一次增加操作(相当于j减一?)

        然后是dp[i][j-1]

        同理相当于s1的前i-1位和s2的前j-1位通过dp[i-1][j-1]已经相等了,但是j比i短了一位,加一位j就可以得到dp[i][j],j做了一次增加操作

        最后是dp[i-1][j-1]

        相当于原本长度为i-1的s1和长度为j-1的s2是相等的,现在s1和s2各加了一位,而且加的还不相等(此处是建立在s1[i]!=s2[j]的基础上才进行判断的)所以需要做一次修改,将两次加的数字修改成一样的

        因为s1[i]!=s2[j],所以无论如何都需要做一步操作才能让新增加的重新变为相等的,因为结果要取操作最少的,所以在三个里面选一个最小的加1,就可以得到方程

        dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;        (当s1[i]!=s2[j])

当s1[i]==s2[j]时,有dp[i][j]=dp[i-1][j-1]

        这个也很好理解原本i-1,j-1为了相等操作了dp[i-1][j-1]次,现在s1和s2的长度都加了1,而且加的数值都一样,说明在i-1,j-1长度的基础上不需要进行操作了,直接相等就可以了

模板

	string a,b;
	cin>>a>>b;        //输入数据
    a.insert(0,1,' ');        //设置首位为空
	b.insert(0,1,' ');        //设置首位为空
	for(int i=0;i<a.size();i++)	dp[i][0]=i;    //初始化
	for(int i=0;i<b.size();i++)	dp[0][i]=i;    //初始化
	for(int i=1;i<=m;i++){        //遍历
		for(int j=1;j<=n;j++){
			if(a[i]==b[j]){        //相等时
				dp[i][j]=dp[i-1][j-1];    //相等的状态转移方程
			}else{                //不相等时
				dp[i][j]=min(dp[i-1][j],min(dp[i][j-1],dp[i-1][j-1]))+1;        
                //不相等的状态转移方程
			}
		}
	}
	cout<<dp[a.size()-1][b.size()-1];    //输出结果

 例题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值