算法->编程之美3.3 计算字符串的相似度

转自:

http://blog.csdn.net/linyunzju/article/details/7747718


问题:

1. 计算两个字符串的最长公共子序列(LCS),且公共子序列在字符串中不需要是连续的。

2. 计算两个字符串的距离,完全相同的字符串距离为0,可以通过修改一个字符、增加一个字符或删除一个字符三种方式来使两个字符串相同,但这些方式会使得距离加1。


1.解法:

这两个问题的解法基本相同,都是二维的动态规划,都考虑字符串的后缀(实际上用动态规划更喜欢考虑前缀,但使用前缀时数组最好从位置1开始,因为dp数组的初始化一般要占用位置0,但字符串不方便从1开始读入,所以在解决问题是使用后缀,用位置n进行初始化)。


f(i,j)表示A从位置i开始的后缀与B从位置j开始的后缀的最长公共子序列Z从位置k开始的后缀的长度。这里的i,j都是阶段,也就是两个阶段变量,状态只有1个,决策有两个即相等或不等。


[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <algorithm>  
  3. #include <cstring>  
  4. using namespace std;  
  5.   
  6. #define MAXN 10001  
  7. char A[MAXN];  
  8. char B[MAXN];  
  9. int dp[MAXN][MAXN];  
  10.   
  11. // 设Z为A和B的最长公共子序列,dp[i][j]表示A从位置i开始的后缀与  
  12. // B从位置j开始的后缀的最长公共子序列Z从位置k开始的后缀的长度  
  13. int main()  
  14. {  
  15.     scanf("%s", A);  
  16.     scanf("%s", B);  
  17.     int i, j, m, n;  
  18.     n = strlen(A);  
  19.     m = strlen(B);  
  20.     // 初始化,若一个序列为空,则最长子序列肯定为0  
  21.     for (i=0; i<=n; i++)  
  22.         dp[i][m] = 0;  
  23.     for (j=0; j<=m; j++)  
  24.         dp[n][j] = 0;  
  25.     for(i=n-1; i>=0; i--)  
  26.         for(j=m-1; j>=0; j--)  
  27.         {  
  28.             if (A[i] == B[j])  
  29.                 // 若相等,则zk=Ai=Bj且A从位置i+1开始的后缀与B从位置j+1开始的后缀  
  30.                 // 的最长公共子序列是Z从位置k+1开始的后缀  
  31.                 dp[i][j]=dp[i+1][j+1]+1;  
  32.             else  
  33.                 // 若不相等,则取两个最长公共子序列中长度较大的那个  
  34.                 dp[i][j]=max(dp[i][j+1], dp[i+1][j]);  
  35.         }  
  36.     for(i=0;i<=n;i++)  
  37.     {  
  38.         for(j=0;j<=m;j++)  
  39.             printf("%d ",dp[i][j]);  
  40.         printf("\n");  
  41.     }  
  42.     printf("%d\n", dp[0][0]);  
  43. }  


2. 解法:

f(i,j)表示字符串A从位置i开始的后缀与字符串B从位置j开始的后缀的距离。这里的i,j都是阶段,也就是两个阶段变量,状态只有1个,决策有两个即相等或不等。

 这里应该是min( ,,).原作者应该是笔误

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <algorithm>  
  3. #include <cstring>  
  4. using namespace std;  
  5.   
  6. #define MAXN 10001  
  7. char A[MAXN];  
  8. char B[MAXN];  
  9. int dp[MAXN][MAXN];  
  10.   
  11. // dp[i][j]表示字符串A从位置i开始的后缀与  
  12. // 字符串B从位置j开始的后缀的距离  
  13. int main()  
  14. {  
  15.     scanf("%s", A);  
  16.     scanf("%s", B);  
  17.     int i, j, m, n;  
  18.     n = strlen(A);  
  19.     m = strlen(B);  
  20.     // 初始化,若一个序列为空,则字符串的距离为  
  21.     // 另一个字符串所取的后缀的长度  
  22.     for (j=m; j>=0; j--)  
  23.         dp[n][j] = m-j;  
  24.     for (i=n; i>=0; i--)  
  25.         dp[i][m] = n-i;  
  26.     for (i=n-1; i>=0; i--)  
  27.         for (j=m-1; j>=0; j--)  
  28.         {  
  29.             if (A[i]==B[j])  
  30.                 // 若相等,则字符串A的字符i与字符串B的字符j并没有增加距离,  
  31.                 // 仍等于A从字符i+1开始的后缀与B从字符j+1开始的后缀的距离  
  32.                 dp[i][j] = dp[i+1][j+1];  
  33.             else  
  34.             {  
  35.                 // 若不相等,则A和B的距离加1,且取相应后缀组中三个距离中最小的那个  
  36.                 dp[i][j] = dp[i+1][j+1]+1;  
  37.                 dp[i][j] = min(dp[i][j], dp[i][j+1]+1);  
  38.                 dp[i][j] = min(dp[i][j], dp[i+1][j]+1);  
  39.             }  
  40.         }  
  41.     for (i=0; i<=n; i++)  
  42.     {  
  43.         for (j=0; j<=m; j++)  
  44.             printf("%d ", dp[i][j]);  
  45.         printf("\n");  
  46.     }  
  47.     printf("%d\n", dp[0][0]);  
  48. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值