Given two strings str1 and str2 and below operations that can be performed on str1. Find the minimum number of edits (operations) required to convert ‘str1’ into ‘str2’.
All of the above operations are of equal cost.
Examples:
Input: str1 = “geek”, str2 = “gesek”
Output: 1
We can convert str1 into str2 by inserting a ‘s’.
Input: str1 = “cat”, str2 = “cut”
Output: 1
We can convert str1 into str2 by replacing ‘a’ with ‘u’.
Input: str1 = “sunday”, str2 = “saturday”
Output: 3
Last three and first characters are same. We basically
need to convert “un” to “atur”. This can be done using
below three operations.
Replace ‘n’ with ‘r’, insert t, insert a
What are the subproblems in this case? The idea is to process all characters one by one starting from either from left or right sides of both strings. Let us traverse from right corner, there are two possibilities for every pair of characters being traversed. The following are the conditions:
- If last characters of two strings are same, nothing much to do. Ignore last characters and get count for remaining strings. So we recur for lengths m-1 and n-1.
- Else (If last characters are not same), we consider all operations on ‘str1’, consider all three operations on last character of first string, recursively compute minimum cost for all three operations, and take minimum of three values.
- Insert: Recur for m and n-1
- Remove: Recur for m-1 and n
- Replace: Recur for m-1 and n-1
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int min( int x, int y, int z)
{
return min(min(x, y), z);
}
int editDist(string str1, string str2, int m, int n)
{
if (m == 0)
return n;
if (n == 0)
return m;
if (str1[m - 1] == str2[n - 1])
return editDist(str1, str2, m - 1, n - 1);
return 1 + min(editDist(str1, str2, m, n - 1),
editDist(str1, str2, m - 1, n),
editDist(str1, str2, m - 1, n - 1)
);
}
int main()
{
string str1 = "sunday" ;
string str2 = "saturday" ;
cout << editDist(str1, str2, str1.length(), str2.length());
return 0;
}
|
Java
class EDIST {
static int min( int x, int y, int z)
{
if (x <= y && x <= z)
return x;
if (y <= x && y <= z)
return y;
else
return z;
}
static int editDist(String str1, String str2, int m, int n)
{
if (m == 0 )
return n;
if (n == 0 )
return m;
if (str1.charAt(m - 1 ) == str2.charAt(n - 1 ))
return editDist(str1, str2, m - 1 , n - 1 );
return 1 + min(editDist(str1, str2, m, n - 1 ),
editDist(str1, str2, m - 1 , n),
editDist(str1, str2, m - 1 , n - 1 )
);
}
public static void main(String args[])
{
String str1 = "sunday" ;
String str2 = "saturday" ;
System.out.println(editDist(str1, str2, str1.length(), str2.length()));
}
}
|
Python
def editDistance(str1, str2, m, n):
if m = = 0 :
return n
if n = = 0 :
return m
if str1[m - 1 ] = = str2[n - 1 ]:
return editDistance(str1, str2, m - 1 , n - 1 )
return 1 + min (editDistance(str1, str2, m, n - 1 ),
editDistance(str1, str2, m - 1 , n),
editDistance(str1, str2, m - 1 , n - 1 )
)
str1 = "sunday"
str2 = "saturday"
print editDistance(str1, str2, len (str1), len (str2))
|
C#
using System;
class GFG {
static int min( int x, int y, int z)
{
if (x <= y && x <= z)
return x;
if (y <= x && y <= z)
return y;
else
return z;
}
static int editDist(String str1, String str2, int m, int n)
{
if (m == 0)
return n;
if (n == 0)
return m;
if (str1[m - 1] == str2[n - 1])
return editDist(str1, str2, m - 1, n - 1);
return 1 + min(editDist(str1, str2, m, n - 1),
editDist(str1, str2, m - 1, n),
editDist(str1, str2, m - 1, n - 1)
);
}
public static void Main()
{
String str1 = "sunday" ;
String str2 = "saturday" ;
Console.WriteLine(editDist(str1, str2, str1.Length,
str2.Length));
}
}
|
Javascript
function min(x, y, z)
{
return Math.min(Math.min(x, y), z);
}
function editDist(str1, str2, m, n)
{
if (m == 0)
return n;
if (n == 0)
return m;
if (str1[m - 1] == str2[n - 1])
return editDist(str1, str2, m - 1, n - 1);
return 1 + min(editDist(str1, str2, m, n - 1),
editDist(str1, str2, m - 1, n),
editDist(str1, str2, m - 1, n - 1)
);
}
var str1 = "sunday" ;
var str2 = "saturday" ;
console.log( editDist(str1, str2, str1.length, str2.length));
|
Space complexity :- O(MN)
The time complexity of above solution is O(3^n) which is exponential. The worst-case happens when none of characters of two strings match. Below is a recursive call diagram for worst case.

We can see that many subproblems are solved, again and again, for example, eD(2, 2) is called three times. Since same subproblems are called again, this problem has Overlapping Subproblems property. So Edit Distance problem has both properties (see this and this) of a dynamic programming problem. Like other typical Dynamic Programming(DP) problems, recomputations of same subproblems can be avoided by constructing a temporary array that stores results of subproblems. The bottom-up approach can be found here.
This code uses top-down dynamic programming and memoization to solve the problem. The repetitive calls in the recursive code can be avoided by using a 2D array to store the results of previous calculations, reducing the time complexity. The 2D array is necessary because two parameters in the recursive calls change value and there are cases of repetitive calls.
Below are the steps:
- Initialize a 2-D DP array of size m *n with -1 at all the index.
- On every recursive call, store the return value at dp[m][n] so that if func(m, n) is called again, it can be answered in O(1) without using recursion.
- Check if the recursive call has been visited previously or not by checking the value at dp[m][n].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
const int maximum = 1000;
int min( int x, int y, int z)
{
return min(min(x, y), z);
}
int editDist(string str1, string str2, int m, int n, int dp[][maximum])
{
if (m == 0)
return n;
if (n == 0)
return m;
if (dp[m - 1][n - 1] != -1)
return dp[m - 1][n - 1];
if (str1[m - 1] == str2[n - 1])
return dp[m - 1][n - 1] = editDist(str1, str2, m - 1, n - 1, dp);
return dp[m - 1][n - 1] = 1 + min(editDist(str1, str2, m, n - 1, dp),
editDist(str1, str2, m - 1, n, dp),
editDist(str1, str2, m - 1, n - 1, dp)
);
}
int main()
{
string str1 = "sunday" ;
string str2 = "saturday" ;
int m = str1.length();
int n = str2.length();
int dp[m][maximum];
memset (dp, -1, sizeof dp);
cout << editDist(str1, str2, m, n, dp);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static int maximum = 1000 ;
static int min( int x, int y, int z)
{
return Math.min((Math.min(x, y)), z);
}
static int editDist(String str1, String str2, int m,
int n, int [][] dp)
{
if (m == 0 )
return n;
if (n == 0 )
return m;
if (dp[m - 1 ][n - 1 ] != - 1 )
return dp[m - 1 ][n - 1 ];
if (str1.charAt(m - 1 ) == str2.charAt(n - 1 ))
return dp[m - 1 ][n - 1 ]
= editDist(str1, str2, m - 1 , n - 1 , dp);
return dp[m - 1 ][n - 1 ]
= 1
+ min(editDist(str1, str2, m, n - 1 ,
dp),
editDist(str1, str2, m - 1 , n,
dp),
editDist(str1, str2, m - 1 , n - 1 ,
dp)
);
}
public static void main(String[] args)
{
String str1 = "sunday" ;
String str2 = "saturday" ;
int m = str1.length();
int n = str2.length();
int [][] dp = new int [m][maximum];
for ( int i = 0 ; i < dp.length; i++)
Arrays.fill(dp[i], - 1 );
System.out.println(editDist(str1, str2, m, n, dp));
}
}
|
Python3
def editDistance(str1, str2, m, n, d = {}):
key = m, n
if m = = 0 :
return n
if n = = 0 :
return m
if key in d:
return d[key]
if str1[m - 1 ] = = str2[n - 1 ]:
return editDistance(str1, str2, m - 1 , n - 1 )
d[key] = 1 + min (editDistance(str1, str2, m, n - 1 ),
editDistance(str1, str2, m - 1 , n),
editDistance(str1, str2, m - 1 , n - 1 ))
return d[key]
str1 = "sunday"
str2 = "saturday"
print (editDistance(str1, str2, len (str1), len (str2)))
|
C#
using System;
class GFG
{
static int maximum = 1000;
static int min( int x, int y, int z)
{
return Math.Min(Math.Min(x, y), z);
}
static int editDist( string str1, string str2, int m,
int n, int [,] dp)
{
if (m == 0)
return n;
if (n == 0)
return m;
if (dp[m - 1, n - 1] != -1)
return dp[m - 1, n - 1];
if (str1[m - 1] == str2[n - 1])
return dp[m - 1, n - 1] = editDist(str1, str2, m - 1, n - 1, dp);
return dp[m - 1, n - 1] = 1 + min(editDist(str1, str2, m, n - 1,
dp),
editDist(str1, str2, m - 1, n,
dp),
editDist(str1, str2, m - 1, n - 1,
dp)
);
}
static void Main( string [] args)
{
string str1 = "sunday" ;
string str2 = "saturday" ;
int m = str1.Length;
int n = str2.Length;
int [,] dp = new int [m, maximum];
for ( int i = 0; i < dp.GetLength(0); i++)
for ( int j = 0; j < dp.GetLength(1); j++)
dp[i, j] = -1;
Console.WriteLine(editDist(str1, str2, m, n, dp));
}
}
|
Javascript
function editDist(str1, str2, m, n, dp) {
if (m === 0) return n;
if (n === 0) return m;
if (dp[m - 1][n - 1] !== undefined) return dp[m - 1][n - 1];
if (str1[m - 1] === str2[n - 1])
return (dp[m - 1][n - 1] = editDist(str1, str2, m - 1, n - 1, dp));
return (dp[m - 1][n - 1] =
1 +
Math.min(
editDist(str1, str2, m, n - 1, dp),
editDist(str1, str2, m - 1, n, dp),
editDist(str1, str2, m - 1, n - 1, dp)
));
}
function main() {
let str1 = "sunday" ;
let str2 = "saturday" ;
let m = str1.length;
let n = str2.length;
let dp = Array(m)
.fill(0)
.map(() => Array(n).fill(undefined));
console.log(editDist(str1, str2, m, n, dp));
}
main();
|
Complexity Analysis:
- Time Complexity: O(M * N)
- Auxiliary Space: O(M * N)