09E-计算字符串距离
09E:计算字符串距离
- 总时间限制:
- 1000ms
- 内存限制:
- 65536kB
- 描述
- 对于两个不同的字符串,我们有一套操作方法来把他们变得相同,具体方法为:
- 修改一个字符(如把“a”替换为“b”)
- 删除一个字符(如把“traveling”变为“travelng”)
比如对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加/减少一个“g”的方式来达到目的。无论增加还是减少“g”,我们都仅仅需要一次操作。我们把这个操作所需要的次数定义为两个字符串的距离。
给定任意两个字符串,写出一个算法来计算出他们的距离。 - 输入
- 第一行有一个整数n。表示测试数据的组数,
接下来共n行,每行两个字符串,用空格隔开。表示要计算距离的两个字符串
字符串长度不超过1000。 - 输出
- 针对每一组测试数据输出一个整数,值为两个字符串的距离。
- 样例输入
-
3 abcdefg abcdef ab ab mnklj jlknm
- 样例输出
-
1 0 4
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int maxlen[1002][1002]; 7 int calc(string a, string b){ 8 memset(maxlen,0,sizeof(maxlen)); 9 int alen = a.length(); 10 int blen = b.length(); 11 for(int i = 1; i <= alen; i++){ 12 maxlen[i][0] = i; 13 } 14 for(int i = 1; i <= blen; i++){ 15 maxlen[0][i] = i; 16 } 17 for(int i = 1; i <= alen; i++){ 18 for(int j = 1; j <= blen; j++){ 19 if(a[i-1]==b[j-1]) maxlen[i][j] = maxlen[i-1][j-1]; 20 else maxlen[i][j] = min(min(maxlen[i-1][j],maxlen[i][j-1]),maxlen[i-1][j-1])+1; 21 } 22 } 23 return maxlen[alen][blen]; 24 } 25 int main(){ 26 int n; 27 cin>>n; 28 while(n--){ 29 string a, b; 30 cin>>a>>b; 31 cout<<calc(a, b)<<endl; 32 } 33 return 0; 34 }
备注:这道题乍一看就跟最长公共子序列非常的相像。但我想错了,我本来想的是求出最长公共子序列然后max(alen,blen)-maxlen[alen][blen]就是结果,也过了样例,但这样其实是不对的,只是我举的例子都比较寸。
比如说abcdeeef,gacdeg这两个序列,按照我的错误想法是4步,但关键就在于第一个g,使得他们的距离是5,也就是说需要先删掉g再在a后面加上b,这是两个步骤。也就是说,我最开始想的是,除了公共子序列之外,以长的那个字符串为基准,短的里面不一样的字母要么就删掉,要么就换掉,要么就添加,但这个显然跟短字符串也有关系。比如说如果短字符串是agcdeg,那么直接把第一个g改成b就行,而不需要先删除再添加这两步。
那这道题正确的想法是什么呢?也和公共子序列很相近。array[i][j]表示a字符串的前i个字符构成的子串和b字符串前j个字符构成的子串,的最小操作数。
对比每一个字符a[i-1]和b[j-1],若两个字符相等,即a[i-1] == b[j-1],则不增加距离,因此对应的数组array[i][j]=array[i-1][j-1];若两个字符不相等,则可删除a[i-1]这个字符、删除b[j-1]这个字符,或修改a[i-1]使它与b[i-1]相等。array[i][j]取这三种方法的最小值。选择修改,则array[i][j] = 1 + array[i-1][j-1],若选择删除a[i-1],则array[i][j] = 1 + array[i-1][j],若选择删除b[i-1],则array[i][j] = 1 + array[i][j-1]。