ACM笔记-动态规划求Levenshtein distance

以HDU 4323为例

首先介绍一下什么叫做Levenshtein distance

编辑距离,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字>符替换成另一个字符,插入一个字符,删除一个字符。
sitten (k→s)

sittin (e→i)

sitting (→g)

俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。

from Wikipedia

动态规划是解决此类问题的常用方法,用二维数组dpi表示源字符串前 i 位变成目标串前 j 位的编辑距离,

dp[i][j] = min( dp[i-1][j]+1 , dp[i][j-1]+1 , dp[i-1][j-1]+!(str1[i]==str2[j]) )

以”sailn”和”failing”这两个字符串作例子,字符串从1开始计数

用矩阵表示为

#0failing
0
s
a
i
l
n

则初始化后为

#0failing
001234567
s1
a2
i3
l4
n5

初始化后,dpi,dp0都已被赋值,现在计算dp1,

dp[0][1]+1=2;dp[1][0]+1=2;dp[0][0]+!(str1[1]==str2[2])=1;

则dp1=1

以此类推,得到最终矩阵

#0failing
001234567
s11234567
a22123456
i33212345
l44321234
n55432223

两字符串的编辑距离就为矩阵最右下角的值

但是在此题中如果计算每对字符串的编辑距离会超时,需要进行一点小优化

题目中给出了两字符串需要满足的最大编辑距离,那么可在计算两字符串编辑距离之前先判断两字符串长度之差,若之差已大于最大距离,那么必然不符合题意,优化后,960ms险过,汗!

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define calLD calLevenshteindistance
using namespace std;
int dp[11][11]={0};
string dict[1501];
 
int min(int a,int b,int c)
{
    int t=(a<b?a:b);
    return (t<c?t:c);
}
int calLD(string s1,string s2,int dis)
{
    memset(dp,0,sizeof(dp));
    int len1=s1.size();
    int len2=s2.size();
    if(len1-len2 <(0-dis) || len1-len2>dis) return 0;
    s1='#'+s1;
    s2='#'+s2;
    int cnt=0;
    for(int i=0;i<=len1;i++) dp[i][0]=i;
    for(int j=0;j<=len2;j++) dp[0][j]=j;
    for(int i=1;i<=len1;i++)
    {
        for(int j=1;j<=len2;j++)
        {
            int flag=(s1[i]!=s2[j]);
            dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+flag);
        }
    }
    return (dp[len1][len2]<=dis);
 
}
int main()
{
//    int res=calLD("kitten","sitting");
//    cout<<res<<endl;
    int t,cas=1;
    cin>>t;
    while(cas<=t)
    {
        //memset(dict,0,sizeof(dict));
        int n,m;
        cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            cin>>dict[i];
        }
        cout<<"Case #"<<cas++<<":\n";
        string toquery="";
        int dis,ans=0;
        for(int i=0;i<m;i++)
        {
            ans=0;
            cin>>toquery>>dis;
            for(int j=0;j<n;j++)
            {
                if(calLD ( toquery,dict[j],dis ))
                     ans++;
            }
            cout<<ans<<endl;
        }
 
    }
    return 0;
}

标签:none

知识共享许可协议
版权声明:本文版权属于作者 plumes,并受法律保护。
本作品采用知识共享「署名 - 非商业性使用 - 相同方式共享 3.0 未本地化版本」许可协议进行许可。