一、题目分析
编辑距离是针对二个字符串的差异程度的量化量测,量测方式是看至少需要多少次处理才能将一个字符串变成另一个字符串。编辑距离可以用在自然语言处理中,例如拼写检查可以根据一个拼错的字和其他正确的字的编辑距离,判断哪一个(或哪几个)是比较可能的字。DNA也可以视为用A、C、G和T组成的字符串,因此编辑距离也用在生物信息学中,判断二个DNA的类似程度。
要求:给定两个序列,假设可以有插入、替换和删除(单个字符)三种编辑操作,设计算法求出这两个序列的最小编辑距离。
示例 1:
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:
输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/edit-distance
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
设计思路
这个问题本质上是一个无向图的问题,固定了起点和终点,起点为字符串 A ,终点为字符串 B 。但是每一个点所对应的分支太多。所以我们需要对其进行转化。在以下特殊情况下,最短编辑距离容易求出三种情况:
1.当 A 、 B 的长度都为 0 时,最短编辑距离为 0
2.当 A 的长度为 0,B 的长度不为0,最短编辑距离为 A 的长度
3.当 A 的长度不为0,B的长度为0,最短编辑距离为 B 的长度
#include<stdio.h>
#include<string.h>
char s1[1000],s2[1000];
int min(int a,int b,int c)
{
int tmp=a<b?a:b;
return tmp<c?tmp:c;
}
void editDistance(int len1,int len2)
{
int **d=new int*[len1+1];
for(int i=0;i<=len1;i++)
d[i]=new int[len2+1];
int i,j;
for(i=0;i<=len1;i++)
d[i][0]=i;
for(j=0;j<=len2;j++)
d[0][j]=j;
for(i=1;i<=len1;i++)
{
for(j=1;j<=len2;j++)
{
int cost=s1[i]==s2[j]?0:1;
int deletion=d[i-1][j]+1;
int insertion=d[i][j-1]+1;
int substitution=d[i-1][j-1]+cost;
d[i][j]=min(deletion,insertion,substitution);
}
}
printf("距离为:%d\n",d[len1][len2]);
for(int i=0;i<=len1;i++)
{
delete[] d[i];
}
delete[] d;
}
int main()
{
while(scanf("%s%s",s1,s2)!=EOF)
{
editDistance(strlen(s1),strlen(s2));
}
}
四、结论
更深一步理解了动态规划,动态规划可以有效地减少不必要的重复计算,从而快速得到最优解。注意main函数中不能申请太大的数组,要把这些定义到外面。动态规划就是逐行逐列地运算,逐渐填满整个数组,最后得到结果恰好保存在数组的最后一行和最后一列的元素上。动态规划中,i和j的增加需要两层循环来完成,外层循环遍历i,内层循环遍历j,也即是,对于每一行,会扫描行内的每一列的元素进行运算。因此,时间复杂度为o(n²),空间复杂度为o(n²)。