动态规划:LeetCode 72(Hard) 编辑距离(简单易理解),思路,步骤和代码实现

动态规划问题

1.LeetCode 72 编辑距离(简单易理解),思路,步骤和代码实现

目标:找到单词1转变为单词2的最少步数。

//例如:
//word1="horse" word2="ros"
//则输出最少步数为:3
//horse->hors
//hors->hos
//hos->ros

思路:不断检测词尾是否一致,原因是词尾一致后dp[i] [j] = dp[i-1] [j-1],例如hors转变为ros的最小步数一定等于hor转变为ro的步数。

  1. 定义二维数组dp[i] [j],其意义为:长度为i的word1转变为长度为j的word2所需的最小步数,这一步对于所有动态规划问题都很重要,至于为什么选择的是二维数组以及为什么根据单词长度来定义,一方面是经验,另一方面因为处理的是两个单词,分别记录检测词尾。

  2. 对各种情况进行分类,在动态规划问题中,基本都需要找到dp[i] [j]与dp[i-1] [j],dp[i] [j-1]以及dp[i-1] [j-1]之间的关系。

    • 词尾相同时

      ​ 词尾相同时显然有dp[i] [j]=dp[i-1] [j-1],例如从hors–>hos的最小步骤等于hor–>ho的最小步骤,这里就体现了检测词尾的另一个好处,i和j在变换的同时,其对应的字母正好就是当前的词尾,例如:hors–>hos,由于词尾相同,则dp[4] [3]=dp[3] [2],word1=[,h,o,r,s],word2=[,h,o,s],word1[4] = word2[3],故i–.j–,dp不变,下一步计算hor–>ho,对比的就是word1[3]和word2[2]。

    • 词尾不同时,可执行:

      1. 增:例如hos–>rose,则需要在word1最后加个e,即dp[i] [j] = dp[i] [j-1] + 1,可以理解为:在hos–>ros的基础上再把word1词尾加了一个e;
      2. 改:例如hos–>ror,则需要将s改为r,即dp[i] [j] = dp[i-1] [j-1] + 1,可以理解为:在ho–>ro的基础上需要加一步将s–>r的步骤;
      3. 删:例如hors–>ror,则需要删掉s,即dp[i] [j] = dp[i-1] [j] + 1,可以理解为:在hor–>ror的基础上需要加一步将s删掉的步骤;
  3. 定义初始条件:设想一下,再不断计算后,总会出现一个i或j变为0,这时候再减就成负数了,故当某一个为0时就是初始条件,因此需要定义dp[0] [m] = m(一个空字符串想变成m个字符的字符串显然是不断增),同理dp[k] [0] = k,但也可根据上文中的词尾不同执行的增改删,当i–成为负数时不执行,只需定义dp[0] [0] =0。

  4. 综上可知:由于定义的dp是最小步数,因此当词尾相同时:dp[i] [j]=dp[i-1] [j-1],当词尾不同时:dp[i] [j] = min{增,删,改}+1,即dp[i] [j] = math.min(dp[i] [j-1],dp[i-1] [j-1],dp[i-1] [j])+1。

实现代码(C++):

#include <iostream>
using namespace std;
int min1(int i,int j,int k)
{
	int a;
	if (i <= j)
		a = i;
	else a = j;
	if (a <= k)
		return a;
	else return k;
}
int main()
{
	string word1,word2;
	word1 = "horse";
	word2 = "ros";
	int m = word1.length();
	int k = word2.length();
	int dp[500][500];
	for (int i = 0; i <= k; i++)	dp[0][i] = i;
	for (int j = 0; j <= m; j++)    dp[j][0] = j;
    for (int i = 1; i <= m; i++)
		for(int j=1;j<=k;j++)
	    {
			if (word1[i-1] == word2[j-1]) 
                dp[i][j] = dp[i - 1][j - 1];	
			else 
                dp[i][j] = min1(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1;
	    }
	cout <<"最少步数为:" << dp[m][k];
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值