Table of Contents

ExplanationImplementation

Editorial (icecuber) (C++)

CPH 7.5 (Edit Distance)

Explanation

We begin by initializing a dp\texttt{dp} array, where dp[i][j]\texttt{dp}[i][j] is the minimum number of edits to convert the first ii characters of the first string, which we denote as str1\texttt{str1}, into the first jj characters of the second string, which we denote as str2\texttt{str2}. The base cases in the dp\texttt{dp} array occur when one of the prefixes is empty.

This means we initialize the dp\texttt{dp} array as follows. Initialize dp[i][0],\texttt{dp}[i][0], where ii is the length of the prefix in str1\texttt{str1}, to be ii because it takes a minimum of ii deletions to convert the first ii characters into the first 00 characters of str2\texttt{str2} (an empty string). Similarly, initialize dp[0][j],\texttt{dp}[0][j], where jj is the length of the prefix in str2\texttt{str2}, to be jj because it takes jj insertions to convert the first 00 characters of str1\texttt{str1} (also an empty string) into the first jj characters of str2\texttt{str2}.

Now that we have initialized our dp\texttt{dp} array, we can move onto the dp[i][j]\texttt{dp}[i][j] transition. The options we have are to delete, insert, or replace a character from str1\texttt{str1}, or do nothing if the current characters are already equal.

When we delete a character, we convert str1[:i1]\texttt{str1}[:i-1] into str2[:j]\texttt{str2}[:j], and then delete str1[i1]\texttt{str1}[i-1]. Therefore, this means that, if the last operation is a deletion, dp[i][j]\texttt{dp}[i][j] is equal to dp[i1][j]+1\texttt{dp}[i - 1][j] + 1, where the extra 11 is the cost of the delete operation.

When we insert a character, we effectively convert str1[:i]\texttt{str1}[:i] into str2[:j1]\texttt{str2}[:j-1], and then insert str2[j1]\texttt{str2}[j-1]. So, dp[i][j]\texttt{dp}[i][j] is equal to dp[i][j1]+1\texttt{dp}[i][j-1] + 1, where the extra 11 is the cost of the insert operation.

Finally, when we replace a character, we essentially convert str1[:i1]\texttt{str1}[:i-1] into str2[:j1]\texttt{str2}[:j-1], then handle the last character. If str1[i1]\texttt{str1}[i-1] and str2[j1]\texttt{str2}[j-1] are different, then that counts as a replacement operation. So, the replacement operation can be represented compactly as

dp[i][j]=dp[i1][j1]+(str1[i1]str2[j1]),\texttt{dp}[i][j] = \texttt{dp}[i - 1][j - 1] + (\texttt{str1}[i - 1] \neq \texttt{str2}[j - 1]),

where str1[i1]str2[j1]\texttt{str1}[i - 1] \neq \texttt{str2}[j - 1] is only 11 when we actually need to replace the letter.

Combining the transition for each operation, the minimum number of edits required to convert the first ii characters in str1\texttt{str1} into the first jj characters of str2\texttt{str2} is

dp[i][j]=min(dp[i1][j]+1, dp[i][j1]+1, dp[i1][j1]+(str1[i1]str2[j1])).\texttt{dp}[i][j] = \min(\texttt{dp}[i - 1][j] + 1,~\texttt{dp}[i][j-1] + 1,~\texttt{dp}[i - 1][j - 1] + (\texttt{str1}[i - 1] \neq \texttt{str2}[j - 1])).

Using this transition, since each state depends only on the cell above, the cell to the left, and the diagonal upper-left cell, we fill the table from top to bottom and left to right. Our final answer is dp[n][m].\texttt{dp}[n][m].

Implementation

Time Complexity: O(NM)\mathcal{O}(NM)

str1 = input()
str2 = input()
"""
dp[i][j] is the minimum number of moves to change the first i letters
of the string into the first j letters of result.
"""
dp = [[0] * (len(str2) + 1) for _ in range(len(str1) + 1)]
# i edits needed to convert first i chars of string 1 into empty string

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!