Given two strings str1 and str2 of length M and N respectively and below operations that can be performed on str1. Find the minimum number of edits (operations) to convert ‘str1‘ into ‘str2‘.
- Operation 1 (INSERT): Insert any character before or after any index of str1
- Operation 2 (REMOVE): Remove a character of str1
- Operation 3 (Replace): Replace a character at any index of str1 with some other character.
Note: All of the above operations are of equal cost.
Examples:
Input: str1 = “geek”, str2 = “gesek”
Output: 1
Explanation: We can convert str1 into str2 by inserting a ‘s’ between two consecutive ‘e’ in str2.
Input: str1 = “cat”, str2 = “cut”
Output: 1
Explanation: We can convert str1 into str2 by replacing ‘a’ with ‘u’.
Input: str1 = “sunday”, str2 = “saturday”
Output: 3
Explanation: 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
Illustration of Edit Distance:
Let’s suppose we have str1=”GEEXSFRGEEKKS” and str2=”GEEKSFORGEEKS”
Now to convert str1 into str2 we would require 3 minimum operations:
Operation 1: Replace ‘X‘ to ‘S‘
Operation 2: Insert ‘O‘ between ‘F‘ and ‘R‘
Operation 3: Remove second last character i.e. ‘K‘
Refer the below image for better understanding.
.png)
Edit Distance using Recursion
Subproblems in Edit Distance:
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:
.png)
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)
Recurrence Relations for Edit Distance:
- EditDistance(str1, str2, M, N) = EditDistance(str1, str2, M-1, N-1)
- Case 1: When the last character of both the strings are same
- Case 2: When the last characters are different
- EditDistance(str1, str2, M, N) = 1 + Minimum{ EditDistance(str1, str2 ,M-1,N-1), EditDistance(str1, str2 ,M,N-1), EditDistance(str1, str2 ,M-1,N) }
Base Case for Edit Distance:
- Case 1: When str1 becomes empty i.e. M=0
- return N, as it require N characters to convert an empty string to str1 of size N
- Case 2: When str2 becomes empty i.e. N=0
- return M, as it require M characters to convert an empty string to str2 of size M
Below is the implementation of the above recursive solution.
C++14
#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;
}
|
C
#include <stdio.h>
#include <string.h>
int min( int x, int y, int z)
{
return x < y ? (x < z ? x : z) : (y < z ? y : z);
}
int editDist( char * str1, char * 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()
{
char str1[] = "sunday" ;
char str2[] = "saturday" ;
int m = strlen (str1);
int n = strlen (str2);
printf ( "%d" , editDist(str1, str2, m, n));
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()));
}
}
|
Python3
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
<script>
function min(x, y, z)
{
if (x <= y && x <= z)
return x;
if (y <= x && y <= z)
return y;
else
return 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));
}
let str1 = "sunday" ;
let str2 = "saturday" ;
document.write(editDist(str1, str2, str1.length,
str2.length));
</script>
|
PHP
<?php
function 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" ;
echo editDistance( $str1 , $str2 , strlen ( $str1 ),
strlen ( $str2 ));
?>
|
Time Complexity: O(3m), when none of the characters of two strings match as shown in the image below.
Auxiliary Space: O(1)
Edit Distance Using Dynamic Programming (Memoization):
In the above recursive approach, there are several overlapping subproblems:
Edit_Distance(M-1, N-1) is called Three times
Edit_Distance(M-1, N-2) is called Two times
Edit_Distance(M-2, N-1) is called Two times. And so on…
So, we can use Memoization technique to store the result of each subproblems to avoid recalculating the result again and again.
Below are the illustration of overlapping subproblems during the recursion.

Overlapping subproblems in the Edit Distance
Below is the implementation of Edit Distance Using Dynamic Programming (Memoization):
C++14
#include <bits/stdc++.h>
using namespace std;
int minDis(string s1, string s2, int n, int m,
vector<vector< int > >& dp)
{
if (n == 0)
return m;
if (m == 0)
return n;
if (dp[n][m] != -1)
return dp[n][m];
if (s1[n - 1] == s2[m - 1]) {
return dp[n][m] = minDis(s1, s2, n - 1, m - 1, dp);
}
else {
int insert, del, replace;
insert = minDis(s1, s2, n, m - 1, dp);
del = minDis(s1, s2, n - 1, m, dp);
replace = minDis(s1, s2, n - 1, m - 1, dp);
return dp[n][m]
= 1 + min(insert, min(del, replace));
}
}
int main()
{
string str1 = "saturday" ;
string str2 = "sunday" ;
int n = str1.length(), m = str2.length();
vector<vector< int > > dp(n + 1, vector< int >(m + 1, -1));
cout << minDis(str1, str2, n, m, dp);
return 0;
}
|
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int min( int x, int y, int z)
{
if (x < y && x < z)
return x;
else if (y < x && y < z)
return y;
else
return z;
}
int minDis( char * s1, char * s2, int n, int m)
{
int dp[n + 1][m + 1];
for ( int i = 0; i <= n; i++) {
for ( int j = 0; j <= m; j++) {
if (i == 0)
dp[i][j] = j;
else if (j == 0)
dp[i][j] = i;
else if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j]
= 1
+ min(dp[i][j - 1],
dp[i - 1][j],
dp[i - 1][j - 1]);
}
}
return dp[n][m];
}
int main()
{
char * str1 = "saturday" ;
char * str2 = "sunday" ;
int n = strlen (str1), m = strlen (str2);
printf ( "%d" , minDis(str1, str2, n, m));
return 0;
}
|
Java
import java.util.*;
class GFG {
static int minDis(String s1, String s2, int n, int m,
int [][] dp)
{
if (n == 0 )
return m;
if (m == 0 )
return n;
if (dp[n][m] != - 1 )
return dp[n][m];
if (s1.charAt(n - 1 ) == s2.charAt(m - 1 )) {
return dp[n][m]
= minDis(s1, s2, n - 1 , m - 1 , dp);
}
else {
int insert, del, replace;
insert = minDis(s1, s2, n, m - 1 , dp);
del = minDis(s1, s2, n - 1 , m, dp);
replace = minDis(s1, s2, n - 1 , m - 1 , dp);
return dp[n][m]
= 1
+ Math.min(insert,
Math.min(del, replace));
}
}
public static void main(String[] args)
{
String str1 = "saturday" ;
String str2 = "sunday" ;
int n = str1.length(), m = str2.length();
int [][] dp = new int [n + 1 ][m + 1 ];
for ( int i = 0 ; i < n + 1 ; i++)
Arrays.fill(dp[i], - 1 );
System.out.print(minDis(str1, str2, n, m, dp));
}
}
|
Python3
def minDis(s1, s2, n, m, dp):
if (n = = 0 ):
return m
if (m = = 0 ):
return n
if (dp[n][m] ! = - 1 ):
return dp[n][m]
if (s1[n - 1 ] = = s2[m - 1 ]):
if (dp[n - 1 ][m - 1 ] = = - 1 ):
dp[n][m] = minDis(s1, s2, n - 1 , m - 1 , dp)
return dp[n][m]
else :
dp[n][m] = dp[n - 1 ][m - 1 ]
return dp[n][m]
else :
if (dp[n - 1 ][m] ! = - 1 ):
m1 = dp[n - 1 ][m]
else :
m1 = minDis(s1, s2, n - 1 , m, dp)
if (dp[n][m - 1 ] ! = - 1 ):
m2 = dp[n][m - 1 ]
else :
m2 = minDis(s1, s2, n, m - 1 , dp)
if (dp[n - 1 ][m - 1 ] ! = - 1 ):
m3 = dp[n - 1 ][m - 1 ]
else :
m3 = minDis(s1, s2, n - 1 , m - 1 , dp)
dp[n][m] = 1 + min (m1, min (m2, m3))
return dp[n][m]
str1 = "saturday"
str2 = "sunday"
n = len (str1)
m = len (str2)
dp = [[ - 1 for i in range (m + 1 )] for j in range (n + 1 )]
print (minDis(str1, str2, n, m, dp))
|
C#
using System;
using System.Collections.Generic;
class GFG {
static int minDis( string s1, string s2, int n, int m,
List<List< int > > dp)
{
if (n == 0)
return m;
if (m == 0)
return n;
if (dp[n][m] != -1)
return dp[n][m];
if (s1[n - 1] == s2[m - 1]) {
if (dp[n - 1][m - 1] == -1) {
return dp[n][m]
= minDis(s1, s2, n - 1, m - 1, dp);
}
else
return dp[n][m] = dp[n - 1][m - 1];
}
else {
int m1, m2, m3;
if (dp[n - 1][m] != -1) {
m1 = dp[n - 1][m];
}
else {
m1 = minDis(s1, s2, n - 1, m, dp);
}
if (dp[n][m - 1] != -1) {
m2 = dp[n][m - 1];
}
else {
m2 = minDis(s1, s2, n, m - 1, dp);
}
if (dp[n - 1][m - 1] != -1) {
m3 = dp[n - 1][m - 1];
}
else {
m3 = minDis(s1, s2, n - 1, m - 1, dp);
}
return dp[n][m]
= 1 + Math.Min(m1, Math.Min(m2, m3));
}
}
static void Main()
{
string str1 = "saturday" ;
string str2 = "sunday" ;
int n = str1.Length, m = str2.Length;
List<List< int > > dp = new List<List< int > >();
for ( int i = 0; i < n + 1; i++) {
dp.Add( new List< int >());
for ( int j = 0; j < m + 1; j++) {
dp[i].Add(-1);
}
}
Console.WriteLine(minDis(str1, str2, n, m, dp));
}
}
|
Javascript
<script>
function minDis(s1,s2,n,m,dp)
{
if (n == 0)
return m;
if (m == 0)
return n;
if (dp[n][m] != -1)
return dp[n][m];
if (s1[n - 1] == s2[m - 1])
{
if (dp[n - 1][m - 1] == -1)
{
return dp[n][m] = minDis(s1, s2, n - 1, m - 1, dp);
}
else
return dp[n][m] = dp[n - 1][m - 1];
}
else
{
let m1, m2, m3;
if (dp[n-1][m] != -1)
{
m1 = dp[n - 1][m];
}
else
{
m1 = minDis(s1, s2, n - 1, m, dp);
}
if (dp[n][m - 1] != -1)
{
m2 = dp[n][m - 1];
}
else
{
m2 = minDis(s1, s2, n, m - 1, dp);
}
if (dp[n - 1][m - 1] != -1)
{
m3 = dp[n - 1][m - 1];
}
else
{
m3 = minDis(s1, s2, n - 1, m - 1, dp);
}
return dp[n][m] = 1 + Math.min(m1, Math.min(m2, m3));
}
}
let str1 = "saturday" ;
let str2 = "sunday" ;
let n= str1.length, m = str2.length;
let dp = new Array(n + 1);
for (let i = 0; i < n + 1; i++)
{
dp[i]= new Array(m+1);
for (let j=0;j<m+1;j++)
dp[i][j]=-1;
}
document.write(minDis(str1, str2, n, m, dp));
</script>
|
Time Complexity: O(m x n)
Auxiliary Space: O( m *n)+O(m+n) , (m*n) extra array space and (m+n) recursive stack space.
Edit Distance Using Dynamic Programming (Bottom-Up Approach):
Use a table to store solutions of subproblems to avoiding recalculate the same subproblems multiple times. By doing this, if same subproblems repeated during, we retrieve the solutions from the table itself.
Below are the steps to convert the recursive approach to Bottom up approach:
1. Choosing Dimensions of Table: The state of smaller sub-problems depends on the input parameters m and n because at least one of them will decrease after each recursive call. So we need to construct a 2D table dp[][] to store the solution of the sub-problems.
2. Choosing Correct size of Table: The size of the 2D table will be equal to the total number of different subproblems, which is equal to (m + 1)*(n + 1). As both m and n are decreasing by 1 during the recursive calls and reaching the value 0. So m + 1 possibilities for the first parameter and n + 1 possibilities for the second parameter. Total number of possible subproblems = (m + 1)*(n + 1).
3. Filling the table: It consist of two stages, table initialization and building the solution from the smaller subproblems:
- Table initialization: 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.
- Building the solution of larger problems from the smaller subproblems: 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]);
4. Returning final solution: After filling the table iteratively, our final solution gets stored at the bottom right corner of the 2-D table i.e. we return Edit[m][n] as an output.
Below is the implementation of the above algorithm:
C++14
#include <bits/stdc++.h>
using namespace std;
int min( int x, int y, int z) { return min(min(x, y), z); }
int editDistDP(string str1, string str2, int m, int n)
{
int dp[m + 1][n + 1];
for ( int i = 0; i <= m; i++) {
for ( int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = j;
else if (j == 0)
dp[i][j] = i;
else if (str1[i - 1] == str2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j]
= 1
+ min(dp[i][j - 1],
dp[i - 1][j],
dp[i - 1][j - 1]);
}
}
return dp[m][n];
}
int main()
{
string str1 = "sunday" ;
string str2 = "saturday" ;
cout << editDistDP(str1, str2, str1.length(),
str2.length());
return 0;
}
|
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int min( int x, int y, int z)
{
if (x <= y && x <= z)
return x;
if (y <= x && y <= z)
return y;
return z;
}
int editDistDP( char * str1, char * str2, int m, int n)
{
int dp[m + 1][n + 1];
for ( int i = 0; i <= m; i++) {
for ( int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = j;
else if (j == 0)
dp[i][j] = i;
else if (str1[i - 1] == str2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j]
= 1
+ min(dp[i][j - 1],
dp[i - 1][j],
dp[i - 1][j - 1]);
}
}
return dp[m][n];
}
int main()
{
char str1[] = "sunday" ;
char str2[] = "saturday" ;
int m = strlen (str1);
int n = strlen (str2);
printf ( "%d\n" , editDistDP(str1, str2, m, n));
return 0;
}
|
Java
import java.io.*;
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 editDistDP(String str1, String str2, int m,
int n)
{
int dp[][] = new int [m + 1 ][n + 1 ];
for ( int i = 0 ; i <= m; i++) {
for ( int j = 0 ; j <= n; j++) {
if (i == 0 )
dp[i][j] = j;
else if (j == 0 )
dp[i][j] = i;
else if (str1.charAt(i - 1 )
== str2.charAt(j - 1 ))
dp[i][j] = dp[i - 1 ][j - 1 ];
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 = "sunday" ;
String str2 = "saturday" ;
System.out.println(editDistDP(
str1, str2, str1.length(), str2.length()));
}
}
|
Python
def editDistDP(str1, str2, m, n):
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 ):
if i = = 0 :
dp[i][j] = j
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 ],
dp[i - 1 ][j],
dp[i - 1 ][j - 1 ])
return dp[m][n]
str1 = "sunday"
str2 = "saturday"
print (editDistDP(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 editDistDP(String str1, String str2, int m,
int n)
{
int [, ] dp = new int [m + 1, n + 1];
for ( int i = 0; i <= m; i++) {
for ( int j = 0; j <= n; j++) {
if (i == 0)
dp[i, j] = j;
else if (j == 0)
dp[i, j] = i;
else if (str1[i - 1] == str2[j - 1])
dp[i, j] = dp[i - 1, j - 1];
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 str1 = "sunday" ;
String str2 = "saturday" ;
Console.Write(editDistDP(str1, str2, str1.Length,
str2.Length));
}
}
|
Javascript
<script>
function min(x,y,z)
{
if (x <= y && x <= z)
return x;
if (y <= x && y <= z)
return y;
else
return z;
}
function editDistDP(str1,str2,m,n)
{
let dp = new Array(m + 1);
for (let i=0;i<m+1;i++)
{
dp[i]= new Array(n+1);
for (let j=0;j<n+1;j++)
{
dp[i][j]=0;
}
}
for (let i = 0; i <= m; i++) {
for (let j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = j;
else if (j == 0)
dp[i][j] = i;
else if (str1[i - 1]
== str2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
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 = "sunday" ;
let str2 = "saturday" ;
document.write(editDistDP(
str1, str2, str1.length, str2.length));
</script>
|
PHP
<?php
function editDistDP( $str1 , $str2 ,
$m , $n )
{
for ( $i = 0; $i <= $m ; $i ++)
{
for ( $j = 0; $j <= $n ; $j ++)
{
if ( $i == 0)
$dp [ $i ][ $j ] = $j ;
else if ( $j == 0)
$dp [ $i ][ $j ] = $i ;
else if ( $str1 [ $i - 1] == $str2 [ $j - 1])
$dp [ $i ][ $j ] = $dp [ $i - 1][ $j - 1];
else
{
$dp [ $i ][ $j ] = 1 + min( $dp [ $i ][ $j - 1],
$dp [ $i - 1][ $j ],
$dp [ $i - 1][ $j - 1]);
}
}
}
return $dp [ $m ][ $n ] ;
}
$str1 = "sunday" ;
$str2 = "saturday" ;
echo editDistDP( $str1 , $str2 , strlen ( $str1 ),
strlen ( $str2 ));
?>
|
Time Complexity: O(m x n)
Auxiliary Space: O(m x n)
Edit Distance Using Dynamic Programming (Optimisation in Space Complexity):
Optimized Space Complexity Solution: In the above bottom up approach we require O(m x n) space. Let’s take an observation and try to optimize our space complexity:
To fill a row in DP array we require only one row i.e. the upper row. For example, if we are filling the row where i=10 in DP array then we require only values of 9th row. So we simply create a DP array of 2 x str1 length. This approach reduces the space complexity from O(N*M) to O(2*N).
Below is the implementation of the above approach:
C++14
#include <bits/stdc++.h>
using namespace std;
class Solution {
public :
int editDistance(string s, string t)
{
int m = s.size();
int n = t.size();
vector< int > prev(n + 1, 0), curr(n + 1, 0);
for ( int j = 0; j <= n; j++) {
prev[j] = j;
}
for ( int i = 1; i <= m; i++) {
curr[0] = i;
for ( int j = 1; j <= n; j++) {
if (s[i - 1] == t[j - 1]) {
curr[j] = prev[j - 1];
}
else {
int mn
= min(1 + prev[j], 1 + curr[j - 1]);
curr[j] = min(mn, 1 + prev[j - 1]);
}
}
prev = curr;
}
return prev[n];
}
};
int main()
{
string s = "saturday" , t = "sunday" ;
Solution ob;
int ans = ob.editDistance(s, t);
cout << ans << "\n" ;
return 0;
}
|
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int min( int a, int b, int c)
{
if (a < b && a < c) {
return a;
}
else if (b < a && b < c) {
return b;
}
else {
return c;
}
}
int editDistance( char * s, char * t)
{
int n = strlen (s);
int m = strlen (t);
int * prev = ( int *) calloc (m + 1, sizeof ( int ));
int * curr = ( int *) calloc (m + 1, sizeof ( int ));
for ( int j = 0; j <= m; j++) {
prev[j] = j;
}
for ( int i = 1; i <= n; i++) {
curr[0] = i;
for ( int j = 1; j <= m; j++) {
if (s[i - 1] == t[j - 1]) {
curr[j] = prev[j - 1];
}
else {
int mn = min(1 + prev[j], 1 + curr[j - 1],
1 + prev[j - 1]);
curr[j] = mn;
}
}
memcpy (prev, curr, (m + 1) * sizeof ( int ));
}
int ans = prev[m];
free (prev);
free (curr);
return ans;
}
int main()
{
char s[] = "saturday" ;
char t[] = "sunday" ;
int ans = editDistance(s, t);
printf ( "%d\n" , ans);
return 0;
}
|
Java
import java.util.*;
class Solution {
public int editDistance(String s, String t)
{
int n = s.length();
int m = t.length();
int [] prev = new int [m + 1 ];
int [] curr = new int [m + 1 ];
for ( int j = 0 ; j <= m; j++) {
prev[j] = j;
}
for ( int i = 1 ; i <= n; i++) {
curr[ 0 ] = i;
for ( int j = 1 ; j <= m; j++) {
if (s.charAt(i - 1 ) == t.charAt(j - 1 )) {
curr[j] = prev[j - 1 ];
}
else {
int mn = Math.min( 1 + prev[j],
1 + curr[j - 1 ]);
curr[j] = Math.min(mn, 1 + prev[j - 1 ]);
}
}
prev = curr.clone();
}
return prev[m];
}
}
public class Main {
public static void main(String[] args)
{
String s = "saturday" ;
String t = "sunday" ;
Solution ob = new Solution();
int ans = ob.editDistance(s, t);
System.out.println(ans);
}
}
|
Python3
class Solution:
def editDistance( self , s: str , t: str ) - > int :
n = len (s)
m = len (t)
prev = [j for j in range (m + 1 )]
curr = [ 0 ] * (m + 1 )
for i in range ( 1 , n + 1 ):
curr[ 0 ] = i
for j in range ( 1 , m + 1 ):
if s[i - 1 ] = = t[j - 1 ]:
curr[j] = prev[j - 1 ]
else :
mn = min ( 1 + prev[j], 1 + curr[j - 1 ])
curr[j] = min (mn, 1 + prev[j - 1 ])
prev = curr.copy()
return prev[m]
s = "saturday"
t = "sunday"
ob = Solution()
ans = ob.editDistance(s, t)
print (ans)
|
C#
using System;
using System.Collections.Generic;
class Solution {
public int EditDistance( string s, string t)
{
int n = s.Length;
int m = t.Length;
List< int > prev = new List< int >();
List< int > curr = new List< int >();
for ( int j = 0; j <= m; j++) {
prev.Add(j);
}
for ( int i = 1; i <= n; i++) {
curr.Add(i);
for ( int j = 1; j <= m; j++) {
if (s[i - 1] == t[j - 1]) {
curr.Add(prev[j - 1]);
}
else {
int mn = Math.Min(1 + prev[j],
1 + curr[j - 1]);
curr.Add(Math.Min(mn, 1 + prev[j - 1]));
}
}
prev = new List< int >(curr);
curr.Clear();
}
return prev[m];
}
}
class Program {
static void Main( string [] args)
{
string s = "saturday" ;
string t = "sunday" ;
Solution ob = new Solution();
int ans = ob.EditDistance(s, t);
Console.WriteLine(ans);
}
}
|
Javascript
class Solution {
editDistance(s, t) {
const n = s.length;
const m = t.length;
const prev = new Array(m + 1).fill(0);
const curr = new Array(m + 1).fill(0);
for (let j = 0; j <= m; j++) {
prev[j] = j;
}
for (let i = 1; i <= n; i++) {
curr[0] = i;
for (let j = 1; j <= m; j++) {
if (s[i - 1] === t[j - 1]) {
curr[j] = prev[j - 1];
} else {
const mn = Math.min(1 + prev[j], 1 + curr[j - 1]);
curr[j] = Math.min(mn, 1 + prev[j - 1]);
}
}
prev.splice(0, m + 1, ...curr);
}
return prev[m];
}
}
const s = "saturday" ;
const t = "sunday" ;
const ob = new Solution();
const ans = ob.editDistance(s, t);
console.log(ans);
|
Time Complexity: O(M x N) where M and N are lengths of the string
Auxiliary Space: O( N ), Length of the str2
Edit Distance Using Dynamic Programming (Further Optimisation in Space Complexity):
As discussed the above approach uses two 1-D arrays, now the question is can we achieve our task by using only a single 1-D array?
The answer is Yes and it requires a simple observation as mentioned below:
In the previous approach The curr[] array is updated using 3 values only :
Value 1: curr[j] = prev[j-1] when str1[i-1] is equal to str2[j-1]
Value 2: curr[j] = prev[j] when str1[i-1] is not equal to str2[j-1]
Value 3: curr[j] = curr[j-1] when str1[i-1] is not equal to str2[j-1]
By keeping the track of these three values we can achiever our task using only a single 1-D array
Below is the code implementation of the approach:
C++14
#include <bits/stdc++.h>
using namespace std;
class Solution {
public :
int editDistance(string str1, string str2)
{
int m = str1.size();
int n = str2.size();
int previous;
vector< int > curr(n + 1, 0);
for ( int j = 0; j <= n; j++) {
curr[j] = j;
}
for ( int i = 1; i <= m; i++) {
previous = curr[0];
curr[0] = i;
for ( int j = 1; j <= n; j++) {
int temp = curr[j];
if (str1[i - 1] == str2[j - 1]) {
curr[j] = previous;
}
else {
curr[j] = 1
+ min({ previous, curr[j - 1],
curr[j] });
}
previous = temp;
}
}
return curr[n];
}
};
int main()
{
string str1 = "sit" , str2 = "kiit" ;
Solution ob;
int ans = ob.editDistance(str1, str2);
cout << ans << "\n" ;
return 0;
}
|
Java
public class EditDistance {
public int editDistance(String str1, String str2) {
int m = str1.length();
int n = str2.length();
int [] curr = new int [n + 1 ];
for ( int j = 0 ; j <= n; j++) {
curr[j] = j;
}
int previous;
for ( int i = 1 ; i <= m; i++) {
previous = curr[ 0 ];
curr[ 0 ] = i;
for ( int j = 1 ; j <= n; j++) {
int temp = curr[j];
if (str1.charAt(i - 1 ) == str2.charAt(j - 1 )) {
curr[j] = previous;
} else {
curr[j] = 1 + Math.min(Math.min(previous, curr[j - 1 ]), curr[j]);
}
previous = temp;
}
}
return curr[n];
}
public static void main(String[] args) {
String str1 = "sit" ;
String str2 = "kiit" ;
EditDistance ed = new EditDistance();
int ans = ed.editDistance(str1, str2);
System.out.println(ans);
}
}
|
Python3
def editDistance(str1, str2):
m = len (str1)
n = len (str2)
curr = [ 0 ] * (n + 1 )
for j in range (n + 1 ):
curr[j] = j
previous = 0
for i in range ( 1 , m + 1 ):
previous = curr[ 0 ]
curr[ 0 ] = i
for j in range ( 1 , n + 1 ):
temp = curr[j]
if str1[i - 1 ] = = str2[j - 1 ]:
curr[j] = previous
else :
curr[j] = 1 + min (previous, curr[j - 1 ], curr[j])
previous = temp
return curr[n]
if __name__ = = "__main__" :
str1 = "sit"
str2 = "kiit"
ans = editDistance(str1, str2)
print (ans)
|
C#
using System;
class GFG
{
static int EditDistance( string str1, string str2)
{
int m = str1.Length;
int n = str2.Length;
int [] curr = new int [n + 1];
for ( int j = 0; j <= n; j++)
{
curr[j] = j;
}
int previous = 0;
for ( int i = 1; i <= m; i++)
{
previous = curr[0];
curr[0] = i;
for ( int j = 1; j <= n; j++)
{
int temp = curr[j];
if (str1[i - 1] == str2[j - 1])
{
curr[j] = previous;
}
else
{
curr[j] = 1 + Math.Min(previous, Math.Min(curr[j - 1], curr[j]));
}
previous = temp;
}
}
return curr[n];
}
static void Main( string [] args)
{
string str1 = "sit" ;
string str2 = "kiit" ;
int ans = EditDistance(str1, str2);
Console.WriteLine(ans);
}
}
|
Javascript
function editDistance(str1, str2) {
const m = str1.length;
const n = str2.length;
const curr = new Array(n + 1).fill(0);
for (let j = 0; j <= n; j++) {
curr[j] = j;
}
let previous = 0;
for (let i = 1; i <= m; i++) {
previous = curr[0];
curr[0] = i;
for (let j = 1; j <= n; j++) {
const temp = curr[j];
if (str1[i - 1] === str2[j - 1]) {
curr[j] = previous;
} else {
curr[j] = 1 + Math.min(previous, curr[j - 1], curr[j]);
}
previous = temp;
}
}
return curr[n];
}
const str1 = "sit" ;
const str2 = "kiit" ;
const ans = editDistance(str1, str2);
console.log(ans);
|
Time Complexity: O(M*N)
Auxiliary Space: O(N)
Real-World Applications of Edit Distance:
- Spell Checking and Auto-Correction
- DNA Sequence Alignment
- Plagiarism Detection
- Natural Language Processing
- Version Control Systems
- String Matching
https://youtu.be/Thv3TfsZVpw
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
04 Nov, 2023
Like Article
Save Article