题目描述:
(题目链接:
最小操作数
)
给定一个原串和目标串,能对源串进行如下操作:
1.在给定位置插入一个字符;
2.替换任意字符 ;
3.删除任意字符。
要求完成一个函数,返回最少的操作数,使得源串进行这些操作后等于目标串。源串和目标串长度都小于2000。
举个例子来直观理解一下这个题目:将kitten字符串转化成sitting需要经过如下三步:
- sitten (k→s)
- sittin (e→i)
- sitting (→g)
因而最少的操作数为3。这个数称为Levenshtein距离或编辑距离,这个概念由俄罗斯科学家Vladimir Levenshtein在1965年提出。
分析:首先定义一个函数edit(i,j),表示第一个字符串的长度为i的子串到第二个字符串的长度为j的子串的编辑距离。经过分析可知edit(i,j)有一下递推公式:
其中,当第一个字符串的第i个字符不等于第二个字符串的第j个字符时,f(i, j) = 1;否则,f(i, j) = 0。
于是原问题转化为一个动态规划的问题。
程序清单如下:
#include <string>
using namespace std;
class Solution {
public:
/**
* 返回从源字符串到目标字符串的最小操作数
* source: 源字符串
* target:目标字符串
* 返回:最小操作数
*/
int min(int a,int b)
{
return (a<b)?a:b;
}
int minOperationCount(string source, string target) {
int len1 = source.length();
int len2 = target.length();
int **res = new int*[len1+1];
for(int i = 0;i<len1+1;++i)
res[i] = new int[len2+1];
for(int i = 0;i<len1+1;++i)
res[i][0] = i;
for(int j = 0;j<len2+1;++j)
res[0][j] = j;
for(int i = 1;i<len1+1;++i)
{
for(int j = 1;j<len2+1;++j)
{
int tmp = min(res[i-1][j]+1,res[i][j-1]+1);
int d;
if(source[i-1] == target[j-1])
d = 0 ;
else
d = 1 ;
res[i][j] = min(tmp,res[i-1][j-1]+d);
}
}
int result = res[len1][len2];
for(int i = 0; i < len1+1; i++)
{
delete[] res[i];
res[i] = NULL;
}
delete[] res;
res = NULL;
return result;
}
};
参考资料: