最小编辑距离

最小编辑距离

编辑距离有两种:

  1. Levenshtein距离: 允许插入,删除和替换一个字符, 最常见
  2. Damerau-Levenshtein距离: 在上者的基础上, 允许交换相邻两字符的位置, 在git中使用
    另外, 操作的权重不同可以分为: 非加权, 和 加权

应用场景:

  • DNA 序列的比对 (两段DNA, 如果编辑距离很小, 说明可能是同源DNA发生了一点突变)
  • 拼写检查, 最接地气的了

LeetCode上第72题(72. 编辑距离 - 力扣(LeetCode) (leetcode-cn.com))

另外CS61a中在作业cat 里也要求实现最小编辑距离

一般两种做法:

  1. 递归( 自顶向下, 会有很多的重复计算, 不过可以采用memo, 但是效果应该还不是很好)
  2. 动规( 自底向上, 采用memo)

string1和string2 都可以插入, 删除, 和替换一个字符, 可以等价为对:

  • string1 插入一个字符
  • string2 插入一个字符 (删除string1的一个字符)
  • 修改string1中的一个字符

且在基础的levenshtein编辑距离中, 三种操作的代价是相同的, 实际上, 他们的代价可以是不同的, 这就是加权编辑距离(可能更符合实际场景), 算法实现, 就是在状态转变的时候加上对应的代价.

动规的一点解释: 二维数组res, res(i)(j), 代表 string1 的前 i 个字符要转化 到 string2 的前 j 个字符需要的编辑距离

另外: 并没有作业要求记录编辑路径, 可以作为拓展作业.

def minimum_mewtations(start, goal, limit):
    """A diff function that computes the edit distance from START to GOAL.
    This function takes in a string START, a string GOAL, and a number LIMIT.

    Arguments:
        start: a starting word
        goal: a goal word
        limit: a number representing an upper bound on the number of edits

    >>> big_limit = 10
    >>> minimum_mewtations("cats", "scat", big_limit)       # cats -> scats -> scat
    2
    >>> minimum_mewtations("purng", "purring", big_limit)   # purng -> purrng -> purring
    2
    >>> minimum_mewtations("ckiteus", "kittens", big_limit) # ckiteus -> kiteus -> kitteus -> kittens
    3
    """
    # assert False, 'Remove this line'
    # def1 iter 缺点: 计算次数多,重复计算, 且没办法提前终止
    def iter_func(s, g, limit):
        if len(s) == 0 or len(g) == 0:
            return max(len(s), len(g))
        elif s[-1] == g[-1]:
            return iter_func(s[:-1], g[:-1], limit)
        else:
            return 1 + min(iter_func(s, g[:-1], limit),iter_func(s[:-1], g,limit),iter_func(s[:-1], g[:-1], limit))
    # return iter_func(start, goal, limit)
    # def2 iter 缺点: 计算次数多,重复计算, 可以采用备忘录的方式来记录计算
    def iter_func(s, g, lim):
        if len(s) == 0 or len(g) == 0:
            return max(len(s), len(g))
        elif s[-1] == g[-1]:
            return iter_func(s[:-1], g[:-1], lim)
        elif lim>= limit:
            return limit + 1;
        else:
            return 1 + min(iter_func(s, g[:-1], lim + 1), iter_func(s[:-1], g, lim + 1), iter_func(s[:-1], g[:-1], lim + 1))
    # return iter_func(start, goal, 0)
    # def3 iter 自底向上, 外加memo (自顶向下也可以)
    def down_up(s, g, limit):
        ls = len(s)
        lg = len(g)
        res_array = [[0 for _ in range(lg + 1)] for _ in range(ls + 1)]
        for x in range(1, lg +1):
            res_array[0][x] = x
        for x in range(1, ls + 1):
            res_array[x][0] = x

        for i in range(1, ls + 1):
            for j in range(1, lg + 1):
                if s[i-1] == g[j-1]:
                    res_array[i][j] = res_array[i-1][j-1]
                else:
                    res_array[i][j] = min(res_array[i-1][j-1] , res_array[i][j-1], res_array[i-1][j]) + 1
        # print(res_array)
        return res_array[-1][-1]
    return down_up(start, goal, limit)
    #todo 记录编辑路径
参考:
  1. https://www.cnblogs.com/arkenstone/p/6196111.html

你可能感兴趣的:(最小编辑距离)