当前位置:编程学习 > C/C++ >>

编程之美系列之计算字符串的相似度

题目描述:也就是给一个源串和目标串,计算最少的操作数,使得源串进行下列操作之后等于目标串。
1、在给定的位置插入字符
2、将当前字符替换成任意字符
3、删除任意字符
题目分析:
如果当前两个字符相等,则结果就是Src+1和Pattern+1两个字符串的最小操作数。
如果不等,就分三种情况:
1、如果是在给定的位置插入字符,那要求的操作数就是Src和Pattern+1两个字符串的最小操作数
2、如果将当前字符替换,那要求的操作数就是Src+1和Pattern+1两个字符串的最小操作数3、如果是删除Src的当前字符,则要求的操作数就是Src+1和Pattern两个字符串的最小操作数
最终结果就是上面三种情况中最小的操作数+1.
递归解法:程序很容易就可以写出来,递归的出口就是某一个字符串到达串尾,则距离就是没有到达串尾的那个字符串的长度。
非递归的解法:就是动态规划,假设dp[i][j]表示Src从第i个字符开始与Pattern从第j个字符开始所求得的最小操作数,动态规划递推的式子如下:
if Src[i] != Pattern[j], dp[i][j] = min(dp[i][j + 1], dp[i + 1][j + 1], dp[i +1][j];
else, dp[i][j] = dp[i + 1][j + 1];
使用动态规划需要注意的地方:
1、递推式中只出现了后面的数据,所以递推的时候应该是从后到前。
2、注意递推时的边界条件的处理。
核心参考代码如下:
 
//递归解法  
int CalStr(const char* Src, const char *Pattern)  
{  
    assert(Src && Pattern);  
    if(*Src == '\0')  
    {  
        return strlen(Pattern);  
    }  
    if(*Pattern == '\0')  
    {  
        return strlen(Src);  
    }  
    if(*Src == *Pattern)  
    {  
        return CalStr(Src + 1, Pattern + 1);  
    }  
    int t1 = CalStr(Src, Pattern + 1);//插入字符  
    int t2 = CalStr(Src + 1, Pattern + 1);//替换字符  
    int t3 = CalStr(Src + 1, Pattern);//删除字符  
    return min(t1, t2, t3) + 1;  
}  
//非递归解法,动态规划  
int CalStrDP(const char *Src, const char *Pattern)  
{  
    assert(Src && Pattern);  
    memset(dp, 0, sizeof(int) * Max_N * Max_N);  
    int nLen1 = strlen(Src);  
    int nLen2 = strlen(Pattern);  
    int i,j;  
    for(i = nLen1 - 1; i >= 0; --i)  
    {  
        for(j = nLen2 - 1; j >= 0; --j)  
        {  
            if(Src[i] == Pattern[j])  
            {  
                dp[i][j] = dp[i + 1][j + 1];  
            }  
            else  
            {  
                if(i < nLen1 - 1 || j < nLen2 - 1)//如果在两个字符串的末尾,则默认初始值为0,直接计算  
                {             
                    if(i + 1 >= nLen1)//设置边界值  
                    {  
                        dp[i + 1][j + 1] = Max_N;  
                        dp[i + 1][j] = Max_N;  
                    }  
                    if(j + 1 >= nLen2)//设置边界值  
                    {  
                        dp[i][j + 1] = Max_N;  
                        dp[i + 1][j + 1] = Max_N;  
                    }  
                }  
                dp[i][j] = min(dp[i][j + 1], dp[i + 1][j + 1], dp[i + 1][j]) + 1;  
            }  
        }  
    }  
    return dp[0][0];  
}  

 

 
下面给出main函数和辅助函数:
 
 
#include<stdio.h>  
#include<string.h>  
#include<assert.h>  
const int Max_N = 100;  
int dp[Max_N][Max_N];  
  
inline int min(const int a, const int b, const int c)  
{  
    int t = a < b ? a : b;  
    return t < c ? t : c;  
}  
  
int main()  
{  
    char Src[Max_N];  
    char Pattern[Max_N];  
    while(gets(Src) && gets(Pattern))  
    {  
        printf("递归:%d\n", CalStr(Src, Pattern));  
        printf("非递归:%d\n", CalStrDP(Src, Pattern));  
    }  
    return 0;  
}  

 

 
 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,