Open In App

CSES Solutions – Edit Distance

Last Updated : 10 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

The edit distance between two strings S1 and S2 is the minimum number of operations required to transform one string into the other.

The allowed operations are:

  • Add one character to the string.
  • Remove one character from the string.
  • Replace one character in the string.

Your task is to calculate the edit distance between two strings.

Examples:

Input: S1 = “LOVE”, S2 = “MOVIE”
Output: 2
Explanation: The two operations required to convert “LOVE” to “MOVIE” are:

  • Replace S1[0] with “M”, so S1 becomes “MOVE”.
  • Add “I” before index 3, so S1 becomes “MOVIE”.

Input: S1 = “L”, S2 = “LOLOLOL”
Output: 6
Explanation: The 6 operations required to convert “L” to “LOLOLOL” are:

  • Add “O” at the last of S1, so S1 becomes “LO”.
  • Add “L” at the last of S1, so S1 becomes “LOL”.
  • Add “O” at the last of S1, so S1 becomes “LOLO”.
  • Add “L” at the last of S1, so S1 becomes “LOLOL”.
  • Add “O” at the last of S1, so S1 becomes “LOLOLO”.
  • Add “L” at the last of S1, so S1 becomes “LOLOLOL”.

Approach: To solve the problem, follow the below idea:

The idea is to process all characters one by one starting from either from left or right sides of both strings. 
Let us process from the right end of the strings, there are two possibilities for every pair of characters being traversed, either they match or they don’t match. If last characters of both string matches then there is no need to perform any operation So, recursively calculate the answer for rest of part of the strings. When last characters do not match, we can perform all three operations to match the last characters in the given strings, i.e. insert, replace, and remove. We then recursively calculate the result for the remaining part of the string. Upon completion of these operations, we will select the minimum answer.

Below is the recursive tree for this problem:


Recursion Tree for Edit Distance


When the last characters of strings matches. Make a recursive call EditDistance(M-1,N-1) to calculate the answer for remaining part of the strings.

When the last characters of strings don’t matches. Make three recursive calls as show below:

  • Insert str1[N-1] at last of str2: EditDistance(M, N-1)
  • Replace str2[M-1] with str1[N-1] : EditDistance(M-1, N-1)
  • Remove str2[M-1] : EditDistance(M-1, N)

Since, the above relation follows optimal substructure and overlapping subproblems, we can use tabulation to compute the result efficiently.

Below are the steps to convert the recursive approach to Bottom up approach:

  • Construct a 2D table dp[m + 1][n + 1] to store the solution of the sub-problems.
  • Before building the solution, we need to initialize the table with the smaller version of the solution i.e. base case. Here m = 0 and n=0 is the situation of the base case, so we initialize first column dp[i][0] with i and first row dp[0][j] with j.
  • We can easily define the iterative structure by using the recursive structure of the above recursive solution.
    • if (str1[i – 1] == str2[j – 1]) dp[i][j] = dp[i – 1][j – 1];
    • if (str1[i – 1] != str2[j – 1]) dp[i][j] = 1 + min(dp[i][j – 1], dp[i – 1][j], dp[i – 1][j – 1]);
  • After filling the table iteratively, our final solution gets stored at the bottom right corner of the 2-D table i.e. we return dp[m][n] as an output.

Below is the implementation of the algorithm:

C++
// A Dynamic Programming based C++ program to find minimum
// number operations to convert str1 to str2
#include <bits/stdc++.h>
using namespace std;

// Utility function to find the minimum of three numbers
int min(int x, int y, int z) { return min(min(x, y), z); }

int editDistDP(string str1, string str2, int m, int n)
{
    // Create a table to store results of subproblems
    int dp[m + 1][n + 1];

    // Fill d[][] in bottom up manner
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            // If first string is empty, only option is to
            // insert all characters of second string
            if (i == 0)
                dp[i][j] = j; // Min. operations = j

            // If second string is empty, only option is to
            // remove all characters of second string
            else if (j == 0)
                dp[i][j] = i; // Min. operations = i

            // If last characters are same, ignore last char
            // and recur for remaining string
            else if (str1[i - 1] == str2[j - 1])
                dp[i][j] = dp[i - 1][j - 1];

            // If the last character is different, consider
            // all possibilities and find the minimum
            else
                dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j],
                                 dp[i - 1][j - 1]);
        }
    }

    return dp[m][n];
}

// Driver code
int main()
{
    // your code goes here
    string str1 = "LOVE";
    string str2 = "MOVIE";

    cout << editDistDP(str1, str2, str1.length(),
                       str2.length());

    return 0;
}
Java
public class Main {
    // Utility function to find the minimum of three numbers
    static int min(int x, int y, int z) {
        return Math.min(Math.min(x, y), z);
    }

    static int editDistDP(String str1, String str2, int m, int n) {
        // Create a table to store results of subproblems
        int[][] dp = new int[m + 1][n + 1];

        // Fill dp[][] in bottom-up manner
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                // If first string is empty, only option is to
                // insert all characters of second string
                if (i == 0)
                    dp[i][j] = j; // Min. operations = j

                // If second string is empty, only option is to
                // remove all characters of second string
                else if (j == 0)
                    dp[i][j] = i; // Min. operations = i

                // If last characters are same, ignore last char
                // and recur for remaining string
                else if (str1.charAt(i - 1) == str2.charAt(j - 1))
                    dp[i][j] = dp[i - 1][j - 1];

                // If the last character is different, consider
                // all possibilities and find the minimum
                else
                    dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]);
            }
        }

        return dp[m][n];
    }

    public static void main(String[] args) {
        String str1 = "LOVE";
        String str2 = "MOVIE";

        System.out.println(editDistDP(str1, str2, str1.length(), str2.length()));
    }
}

// This code is contributed by shivamgupta0987654321
Python3
# Utility function to find the minimum of three numbers
def minimum(x, y, z):
    return min(x, min(y, z))

def editDistDP(str1, str2, m, n):
    # Create a table to store results of subproblems
    dp = [[0] * (n + 1) for _ in range(m + 1)]

    # Fill dp[][] in bottom-up manner
    for i in range(m + 1):
        for j in range(n + 1):
            # If first string is empty, only option is to
            # insert all characters of second string
            if i == 0:
                dp[i][j] = j  # Min. operations = j

            # If second string is empty, only option is to
            # remove all characters of second string
            elif j == 0:
                dp[i][j] = i  # Min. operations = i

            # If last characters are same, ignore last char
            # and recur for remaining string
            elif str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1]

            # If the last character is different, consider
            # all possibilities and find the minimum
            else:
                dp[i][j] = 1 + minimum(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1])

    return dp[m][n]

if __name__ == "__main__":
    str1 = "LOVE"
    str2 = "MOVIE"

    print(editDistDP(str1, str2, len(str1), len(str2)))
JavaScript
// Utility function to find the minimum of three numbers
function min(x, y, z) {
    return Math.min(Math.min(x, y), z);
}

function editDistDP(str1, str2, m, n) {
    // Create a table to store results of subproblems
    let dp = Array(m + 1).fill().map(() => Array(n + 1).fill(0));

    // Fill dp[][] in bottom-up manner
    for (let i = 0; i <= m; i++) {
        for (let j = 0; j <= n; j++) {
            // If first string is empty, only option is to
            // insert all characters of second string
            if (i == 0)
                dp[i][j] = j; // Min. operations = j

            // If second string is empty, only option is to
            // remove all characters of second string
            else if (j == 0)
                dp[i][j] = i; // Min. operations = i

            // If last characters are same, ignore last char
            // and recur for remaining string
            else if (str1.charAt(i - 1) == str2.charAt(j - 1))
                dp[i][j] = dp[i - 1][j - 1];

            // If the last character is different, consider
            // all possibilities and find the minimum
            else
                dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]);
        }
    }

    return dp[m][n];
}

let str1 = "LOVE";
let str2 = "MOVIE";

console.log(editDistDP(str1, str2, str1.length, str2.length));

Output
2

Time Complexity: O(n * m), where n and m are the length of input strings.
Auxiliary Space: O(n * m)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads