[算法 --- 1] 动态规划求解编辑距离问题

动态规划求解编辑距离问题

[算法 --- 1] 动态规划求解编辑距离问题_第1张图片

一. 问题定义

        给定两个字符串s1, s2,只能用以下三种操作: 插入,删除,替换一个字符,将字符串s1转换为s2。

二. 基本思路

        补充: 求解动态规划问题的四个步骤

        解决两个字符串的动态规划问题,一般都是先用两个指针i, j分别指向两个字符串的开始或者最后,然后再一步步向前走,

缩小问题的规模。

 

假设需要将字符串s1 = "rapd" 替换为字符串 s2 = "apple",将字符串s2转换为s1,至少需要以下步骤:

        s1 = a  p  p  l  e 

        s2 = r  a  p  d

(1) 删除,此时s2 = a p d

(2) 不变,此时s2 = a p d

(3) 不变,此时s2 = a p d

(4) 替换,此时s2 = a p p

(5) 添加,此时s2 = a p p l

(6) 添加,此时s2 = a p p l e

        题主之间考虑过一种错误的思路,保持s1不变,从s2的第一个位置开始,最少也需要5次替换哇,但实际上忽略了动态规划的一个基本要求--初始条件。

        在本例中,将指针 i 指向字符串 s1 的第 i - 1 个位置,将指针 j 指向字符串 s2 的第 j - 1 个位置。设字符串s2[0:j - 1]转换到字符串s1[0:i - 1]最少需要的编辑距离为d[i][j],此时 i 和 j 还可以表示字符串 s1 和 s2 的长度。

初始条件为

当i = 0, j = 0,此时字符串 s1 和 s2 都为空, d[i][j] = 0

当i = 0,j > 0,此时字符串s1为空,字符串s2不为空,d[i][j] = j

当i > 0,j = 0,此时字符串s1不为空,字符串s2为空,d[i][j] = 1

用公式表示为

d[i][j] = \left\{\begin{matrix} & 0 \quad if \quad i = 0, j = 0\\ & i \quad if \quad i > 0, j = 0\\ & j \quad if \quad i = 0, j > 0 \end{matrix}\right.

再回到刚才的错误思路,保持s1不变,s2的第一个位置开始时,i = 1,j = 1,d[i][j] = d[1][1],此时只能替换。d[1][2]开始就存在区分度。

        考虑以下几种情况:

(1) s1[i] == s2[j]

例如,不变

        s1[0:i] = a b c d

        s2[0:j] = a b c d

此时保持不变的代价最小,d[i][j] = d[i - 1][j - 1]

 

(2) s1[i] != s[j],考虑3种操作的最小值,每次操作只针对字符串 s2 的当前字符。

例如,替换操作

        s1[0:i] = a b c d

        s2[0:j] = a b c e

此时替换操作的代价最小,d[i][[j] = d[i - 1][j - 1] + 1

 

例如,插入操作

        s1[0: i] = a b c d

        s2[o: j] =    a b c

此时插入操作的代价最小,d[i][j] = d[i - 1][j] + 1

 

例如,删除操作

        s1[0: i] = a b c d

        s2[0: j] = a b c d e

此时删除操作的代价最小,d[i][j] = d[i][j - 1] + 1

 

综上所述,

d[i][j]=\left\{\begin{matrix} & d[i - 1][j - 1], if \ s[i] == s[j] \\ & min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + 1), if \ s[i] \neg s[j] \end{matrix}\right.

三. 代码实现

Python实现代码如下:

# python3 实现编辑距离算法(Levenshtein距离)
def edit_distance(text1, text2):
    len1 = len(text1)
    len2 = len(text2)

    distance = numpy.zeros((len1 + 1, len2 + 1))

    # 初始化
    distance[0][0] = 0
    for idx in range(1, len1 + 1):
        distance[idx][0] = idx
    for idx in range(1, len2 + 1):
        distance[0][idx] = idx

    for idx1 in range(1, len1 + 1):
        for idx2 in range(1, len2 + 1):
            if text1[idx1 - 1] == text2[idx2 - 1]:
                distance[idx1][idx2] = distance[idx1 - 1][idx2 - 1]
            else:
                min = max(len1, len2)
                if distance[idx1 - 1][idx2] + 1 < min:
                    min = distance[idx1 - 1][idx2] + 1  # 删除
                if distance[idx1][idx2 - 1] + 1 < min:
                    min = distance[idx1][idx2 - 1] + 1  # 添加
                if distance[idx1 - 1][idx2 - 1] + 1 < min:
                    min = distance[idx1 - 1][idx2 - 1] + 1  # 替换
                distance[idx1][idx2] = min
    return distance

四. 编辑距离变体

Damerau-Levenshtein 距离

你可能感兴趣的:(数据结构与算法)