算法——动态规划算法求解字符串的编辑距离

当有人让你用递归算法求解斐波那契数列以及字符串的编辑距离时,所设的陷阱都是一致的(递归调用时的重复计算),解决方案也是一致的(引入备忘录概念)。观察树形的层级调用关系,我们可以发现动态规划隐式地嵌入了一种剪枝机制。

动态规划版求解菲波那切数列

关于朴素递归求解菲波那切数列存在的重复计算的说明:

这里写图片描述

红色部分均是重复计算项,当递归调用的层次更多时,重复计算的问题更为严重。

unsigned __int64 memo[1000];
unsigned __int64 fib(size_t n)
{
    if (n<=1)
        return n;
    if (memo[n])
        return memo[n];
    return memo[n] = fib(n-1) + fib(n-2);
            // 赋值运算(=)的也存在返回值,返回值是`=`号左侧的值
            // 对于第一次计算得到的值进行记录备份,
            // 下次如果想得到该值,先进性判断是否已经计算过了
            // 如果是,直接返回,见第二个if
}

动态规划版求解字符串编辑距离

我们来看朴素递归来求解字符串编辑距离时可能出现的重复计算的问题(5, 5:表示的是,源字符串和目标字符串各自的长度为5):


这里写图片描述

现在我们应用动态规划的思想对朴素递归算法进行改造,所谓动态规划,其核心有二:

  1. 状态的概念

    为递归接口增加状态标识参数 i j

    int editDist(char* src, char* dst);

    改造为(引入状态的概念):

    int editDist(char* src, char* dst, int i, int j);
  2. 备忘录概念

    通过定义相关的结构体实现

    typedef struct tagMemoRecord
    {
        int dist;
        int refCount;
    }MEMO_RECORD;
    // 作为全局变量
    vector<vector<MEMO_RECORD>> memo(100, vector<MEMO_RECORD>(100));
int editDist(char* src, char* dst, int i, int j)
{
    if (memo[i][j].refCount)
    {
        ++memo[i][j].refCount;
        return memo[i][j].dist;
    }
    int dist = 0;
    if (strlen(src+i) == 0)
    {
        dist = strlen(dst+j);
    }
    else if(strlen(dst+j) == 0)
    {
        dist = strlen(src+i);
    }
    else
    {
        if (src[i] == dst[j])
        {
            dist = editDist(src, dst, i+1, j+1);
        }
        else
        {
            int editIns = editDist(src, dst, i, j+1) + 1;
            int editDel = editDist(src, dst, i+1, j) + 1;
            int editRep = editDist(src, dst, i+1, j+1) + 1;
            dist = std::min({editIns, editDel, editRep});
        }
    }
    memo[i][j].refCount = 1;
    return memo[i][j].dist = dist;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值