dynamic-programming-edit-distance-problem

動態規劃 編輯距離問題(Edit Distance Problem)
網址鏈接:https://algorithms.tutorialhorizon.com/dynamic-programming-edit-distance-problem/

  1. 目標:

給定兩個字符串s1, s2,寫出一個算法來找出從s1轉化到s2所需要的最小操作步驟數(編輯距離)。

所允許的操作:

Insert(插入)——插入一個新的字符

delete(刪除)——刪除一個字符

replace(替換) ——替換爲另一個字符

例子:

s1 = "horizon"
s2 = "horzon"
Output: 1  {remove 'i' from string s1}
 
s1 = "horizon"
s2 = "horizontal"
Output: 3  {insert 't', 'a', 'l' characters in string s1}
  1. 方法:

同時比較兩個字符串中的一個字符。在這裏,我們從右到左(從後到前backwards)比較字符串。

現在對於每個字符串,我們有兩種選擇:

如果兩個字符串中的最後一個字符是相同的,則忽略最後這個字符,然後再同時比較倒數第二個字符,一直比較下去,知道兩個字符相同,就進入第二種情況(類似於遞歸的解決剩餘的字符)

如果兩個字符串中的最後一個字符不相同,那麼就嘗試上述三種操作(insert,replace,delete)使得最後一個字符相同。並且爲每種可能性遞歸獲取剩餘字符串的解決方案,並從中選擇最小值。

假設給定的字符串分別是s1和s2,長度分別爲m和n:

case1:最後一個字符相同,遞歸的求解剩餘的m-1,n-1個字符

case2:最後一個字符不相同,然後遞歸嘗試所有可能的操作。

將一個字符插入s1中(插入的字符要與字符串s2中的最後一個字符相同,以便兩個字符串中的最後一個字符相同):現在s1的長度將爲m + 1,s2的長度爲n,忽略最後一個字符並遞歸求解剩餘的m,n -1個字符。

從字符串s1中刪除最後一個字符。現在s1長度將是m-1,s2長度爲n,遞歸求解m-1,n。

將最後一個字符替換爲s1(與字符串s2中的最後一個字符相同,以便兩個字符串中的最後一個字符相同):s1的長度爲m,s2的長度爲n,忽略最後一個字符,然後遞歸求解m-1,n- 1。

選擇(a,b,c)中的最小值。 首先,我們將看到遞歸解決方案,然後將通過使用動態編程降低其複雜性來改進解決方案。

# 基於遞歸的解決方法
def edit_dist(str1, str2, m, n):
    if m == 0:
        return n
    if n == 0:
        return m
     
    if str1[m-1] == str2[n-1]:
        return edit_dist(str1, str2, m-1, n-1)
     
    return 1 + min(edit_dist(str1, str2, m, n-1),
                   edit_dist(str1, str2, m-1, n),
                   edit_dist(str1, str2, m-1, n-1))
s1 = "horizon"
s2 = "horizontal"
print(edit_dist(s1, s2, len(s1), len(s2)))

輸出結果:
3

讓我們分析上述解決方案。 在最壞的情況下,我們需要對字符串的每個字符執行操作,因爲我們有3次操作,所以時間複雜度將爲O(3 ^ n)。

讓我們看看是否存在重疊的子問題。例: 字符串s1:“ CAT”,字符串s2:“ DOG”

正如我們看到的那樣,有很多子問題可以反覆解決,因此在這裏有很多重疊的子問題。我們可以通過自底向上的方式使用動態編程來解決它。 我們將解決問題並將其存儲到數組中(維護數組),並根據需要使用解決方案,以確保每個子問題僅被解決一次。

# 基於動態規劃的解法
def dp_edit_dist(str1, str2):
     
    # m,n分別字符串str1和str2的長度
    m, n = len(str1), len(str2)
     
    # 構建二位數組來存儲子問題(sub-problem)的答案
    dp = [[0 for x in range(n+1)] for x in range(m+1)]
       
    # 利用動態規劃算法,填充數組
    for i in range(m+1):
        for j in range(n+1):
   
            # 假設第一個字符串爲空,則轉換的代價爲j (j次的插入)
            if i == 0:
                dp[i][j] = j   
               
            # 同樣的,假設第二個字符串爲空,則轉換的代價爲i (i次的插入)
            elif j == 0:
                dp[i][j] = i
             
            # 如果最後一個字符相等,就不會產生代價
            elif str1[i-1] == str2[j-1]:
                dp[i][j] = dp[i-1][j-1]
   
            # 如果最後一個字符不一樣,則考慮多種可能性,並且選擇其中最小的值
            else:
                dp[i][j] = 1 + min(dp[i][j-1],        # Insert
                                   dp[i-1][j],        # Remove
                                   dp[i-1][j-1])      # Replace
   
    return dp[m][n]

註釋:

在計算機科學中,編輯距離是一種通過計算將一個字符串轉換爲另一個字符串所需的最小操作數量來量化兩個字符串(例如單詞)彼此之間有多不同的方式。編輯距離可以在自然語言處理中找到應用之處,如其中自動拼寫校正可以通過從字典中選擇與所討論單詞的距離較小的單詞來確定拼寫錯誤的單詞的對其進行更正。在生物信息學中,它可以用於量化DNA序列的相似性,可以將其視爲字母A,C,G和T的字符串。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章