Prerequisite: Dynamic Programming | Set 5 (Edit Distance)
Given two strings str1 and str2, the task is to print the all possible ways to convert ‘str1’ into ‘str2’.
Below are the operations that can be performed on “str1”:
- Insert
- Remove
- Replace
All of the above operations are of equal cost. The task is to print all the various ways to convert ‘str1’ into ‘str2’ using the minimum number of edits (operations) required, where a “way” comprises of the series of all such operations required.
Examples:
Input: str1 = “abcdef”, str2 = “axcdfdh”
Output:
Method 1:
Add h
Change f to d
Change e to f
Change b to x
Method 2:
Change f to h
Add d
Change e to f
Change b to x
Method 3:
Change f to h
Change e to d
Add f
Change b to x
Approach for printing one possible way:
The approach for finding the minimum number of edits has been discussed in this post. To print one possible way, iterate from the bottom right corner of the DP matrix formed using Min-Edit Distance method. Check if the character pertaining to that element in both strings is equal or not. If it is, it means it needs no edit, and DP[i][j] was copied from DP[i-1][j-1].
If str1[i-1] == str2[j-1], proceed diagonally.
Note that since the DP matrix contains one extra row and column at 0 indices, String indexes will be decreased by one. i.e. DP[i][j] corresponds to i-1 index of str1 and j-1 index of str2.
Now, if the characters were not equal, that means this matrix element DP[i][j] was obtained from the minimum of DP[i-1][j-1], DP[i][j-1] and DP[i-1][j], plus 1. Hence, check from where this element was from.
1. If DP[i][j] == DP[i-1][j-1] + 1
It means the character was replaced from str1[i] to str2[j]. Proceed diagonally.
2. If DP[i][j] == DP[i][j-1] + 1
It means the character was Added from str2[j]. Proceed left.
3. If DP[i][j] == DP[i-1][j] + 1
It means the character str1[i] was deleted. Proceed up.
Once the end i.e., (i==0 and j==0 ) of both strings is reached, converting of one string to other is done. We will have printed all the set of operations required.
Below is the implementation of the above approach:
// C++ program to print one possible // way of converting a string to another #include <bits/stdc++.h> using namespace std;
int DP[100][100];
// Function to print the steps void printChanges(string s1, string s2,
int dp[][100])
{ int i = s1.length();
int j = s2.length();
// check till the end
while (i and j)
{
// if characters are same
if (s1[i - 1] == s2[j - 1])
{
i--;
j--;
}
// Replace
else if (dp[i][j] == dp[i - 1][j - 1] + 1)
{
cout << "change " << s1[i - 1]
<< " to " << s2[j - 1] << endl;
i--;
j--;
}
// Delete the character
else if (dp[i][j] == dp[i - 1][j] + 1)
{
cout << "Delete " << s1[i - 1] << endl;
i--;
}
// Add the character
else if (dp[i][j] == dp[i][j - 1] + 1)
{
cout << "Add " << s2[j - 1] << endl;
j--;
}
}
} // Function to compute the DP matrix void editDP(string s1, string s2)
{ int l1 = s1.length();
int l2 = s2.length();
DP[l1 + 1][l2 + 1];
// initialize by the maximum edits possible
for ( int i = 0; i <= l1; i++)
DP[i][0] = i;
for ( int j = 0; j <= l2; j++)
DP[0][j] = j;
// Compute the DP matrix
for ( int i = 1; i <= l1; i++)
{
for ( int j = 1; j <= l2; j++)
{
// if the characters are same
// no changes required
if (s1[i - 1] == s2[j - 1])
DP[i][j] = DP[i - 1][j - 1];
else
// minimum of three operations possible
DP[i][j] = min(min(DP[i - 1][j - 1],
DP[i - 1][j]),
DP[i][j - 1]) + 1;
}
}
// print the steps
printChanges(s1, s2, DP);
} // Driver Code int main()
{ string s1 = "abcdef" ;
string s2 = "axcdfdh" ;
// calculate the DP matrix
editDP(s1, s2);
return 0;
} // This code is contributed by // sanjeev2552 |
import java.util.*;
class FollowUp_PrintOneWayToConvert {
public static void main(String[] args) {
var o = new FollowUp_PrintOneWayToConvert();
o.minDistance( "abcdef" , "axcdfdh" );
for (var r : o.dp) System.out.println(Arrays.toString(r));
o.printChanges( "abcdef" , "axcdfdh" );
// Only add: GeeksForGeeks impl won't print added chars
o = new FollowUp_PrintOneWayToConvert();
o.minDistance( "" , "abc" );
for (var r : o.dp) System.out.println(Arrays.toString(r));
o.printChanges( "" , "abc" );
// Only remove: GeeksForGeeks impl won't print removed chars
o = new FollowUp_PrintOneWayToConvert();
o.minDistance( "abc" , "" );
for (var r : o.dp) System.out.println(Arrays.toString(r));
o.printChanges( "abc" , "" );
}
int [][] dp;
int minDistance(String s, String targ) {
int m = s.length(), n = targ.length();
dp = new int [m + 1 ][n + 1 ];
// initialize by the maximum edits possible
for ( int i = 0 ; i <= m; i++) dp[i][ 0 ] = i;
for ( int j = 0 ; j <= n; j++) dp[ 0 ][j] = j;
for ( int i = 1 ; i <= m; i++)
for ( int j = 1 ; j <= n; j++)
if (s.charAt(i - 1 ) == targ.charAt(j - 1 )) dp[i][j] = dp[i - 1 ][j - 1 ];
else dp[i][j] = 1 + Math.min(dp[i - 1 ][j - 1 ], Math.min(dp[i - 1 ][j], dp[i][j - 1 ]));
return dp[m][n];
}
void printChanges(String s, String t) {
int i = s.length(), j = t.length();
while (i > 0 && j > 0 ) {
// Match(if characters same):
if (s.charAt(i - 1 ) == t.charAt(j - 1 )) { i--; j--; }
// No match:
// Replace
else if (dp[i][j] == dp[i - 1 ][j - 1 ] + 1 ) { System.out.println( "Change " + s.charAt(i - 1 ) + " to " + t.charAt(j - 1 )); i--; j--; }
// Delete the character
else if (dp[i][j] == dp[i - 1 ][j] + 1 ) { System.out.println( "Delete " + s.charAt(i - 1 )); i--; }
// Add character
else if (dp[i][j] == dp[i][j - 1 ] + 1 ) { System.out.println( "Add " + t.charAt(j - 1 )); j--; }
} // i or j == 0, so we need to only remove or add chars
while (i > 0 ) System.out.println( "Delete " + s.charAt(--i)); // 't' matched but some 's' chars left not removed - rm all 's' chars
while (j > 0 ) System.out.println( "Add " + t.charAt(--j)); // 's' chars finished but not all 't' chars matched - add missing
}
} |
# Python3 program to print one possible # way of converting a string to another # Function to print the steps def printChanges(s1, s2, dp):
i = len (s1)
j = len (s2)
# Check till the end
while (i > 0 and j > 0 ):
# If characters are same
if s1[i - 1 ] = = s2[j - 1 ]:
i - = 1
j - = 1
# Replace
elif dp[i][j] = = dp[i - 1 ][j - 1 ] + 1 :
print ( "change" , s1[i - 1 ],
"to" , s2[j - 1 ])
j - = 1
i - = 1
# Delete
elif dp[i][j] = = dp[i - 1 ][j] + 1 :
print ( "Delete" , s1[i - 1 ])
i - = 1
# Add
elif dp[i][j] = = dp[i][j - 1 ] + 1 :
print ( "Add" , s2[j - 1 ])
j - = 1
# Function to compute the DP matrix def editDP(s1, s2):
len1 = len (s1)
len2 = len (s2)
dp = [[ 0 for i in range (len2 + 1 )]
for j in range (len1 + 1 )]
# Initialize by the maximum edits possible
for i in range (len1 + 1 ):
dp[i][ 0 ] = i
for j in range (len2 + 1 ):
dp[ 0 ][j] = j
# Compute the DP Matrix
for i in range ( 1 , len1 + 1 ):
for j in range ( 1 , len2 + 1 ):
# If the characters are same
# no changes required
if s2[j - 1 ] = = s1[i - 1 ]:
dp[i][j] = dp[i - 1 ][j - 1 ]
# Minimum of three operations possible
else :
dp[i][j] = 1 + min (dp[i][j - 1 ],
dp[i - 1 ][j - 1 ],
dp[i - 1 ][j])
# Print the steps
printChanges(s1, s2, dp)
# Driver Code s1 = "abcdef"
s2 = "axcdfdh"
# Compute the DP Matrix editDP(s1, s2) # This code is contributed by Pranav S |
// C# program to print one possible // way of converting a string to another using System;
public class GFG
{ static int [,]dp;
// Function to print the steps
static void printChanges(String s1, String s2)
{
int i = s1.Length;
int j = s2.Length;
// check till the end
while (i != 0 && j != 0)
{
// if characters are same
if (s1[i - 1] == s2[j - 1])
{
i--;
j--;
}
// Replace
else if (dp[i, j] == dp[i - 1, j - 1] + 1)
{
Console.WriteLine( "change " + s1[i - 1] + " to " + s2[j - 1]);
i--;
j--;
}
// Delete the character
else if (dp[i, j] == dp[i - 1, j] + 1)
{
Console.WriteLine( "Delete " + s1[i - 1]);
i--;
}
// Add the character
else if (dp[i, j] == dp[i, j - 1] + 1)
{
Console.WriteLine( "Add " + s2[j - 1]);
j--;
}
}
}
// Function to compute the DP matrix
static void editDP(String s1, String s2)
{
int l1 = s1.Length;
int l2 = s2.Length;
int [,] DP = new int [l1 + 1, l2 + 1];
// initialize by the maximum edits possible
for ( int i = 0; i <= l1; i++)
DP[i, 0] = i;
for ( int j = 0; j <= l2; j++)
DP[0, j] = j;
// Compute the DP matrix
for ( int i = 1; i <= l1; i++)
{
for ( int j = 1; j <= l2; j++)
{
// if the characters are same
// no changes required
if (s1[i - 1] == s2[j - 1])
DP[i, j] = DP[i - 1, j - 1];
else
{
// minimum of three operations possible
DP[i, j] = min(DP[i - 1, j - 1],
DP[i - 1, j], DP[i, j - 1])
+ 1;
}
}
}
// initialize to global array
dp = DP;
}
// Function to find the minimum of three
static int min( int a, int b, int c)
{
int z = Math.Min(a, b);
return Math.Min(z, c);
}
// Driver Code
public static void Main(String[] args)
{
String s1 = "abcdef" ;
String s2 = "axcdfdh" ;
// calculate the DP matrix
editDP(s1, s2);
// print the steps
printChanges(s1, s2);
}
} // This code is contributed by PrinciRaj1992 |
// Javascript code for the above approach let DP = Array(100).fill().map(() => Array(100).fill(0)); function printChanges(s1, s2, dp) {
let i = s1.length;
let j = s2.length;
// check till the end
while (i && j) {
// if characters are same
if (s1[i - 1] === s2[j - 1]) {
i--;
j--;
}
// Replace
else if (dp[i][j] === dp[i - 1][j - 1] + 1) {
console.log(`change ${s1[i - 1]} to ${s2[j - 1]<br>}`);
i--;
j--;
}
// Delete the character
else if (dp[i][j] === dp[i - 1][j] + 1) {
console.log(`Delete ${s1[i - 1]}<br>`);
i--;
}
// Add the character
else if (dp[i][j] === dp[i][j - 1] + 1) {
console.log(`Add ${s2[j - 1]}<br>`);
j--;
}
}
} function editDP(s1, s2) {
let l1 = s1.length;
let l2 = s2.length;
// initialize by the maximum edits possible
for (let i = 0; i <= l1; i++) {
DP[i][0] = i;
}
for (let j = 0; j <= l2; j++) {
DP[0][j] = j;
}
// Compute the DP matrix
for (let i = 1; i <= l1; i++) {
for (let j = 1; j <= l2; j++) {
// if the characters are same
// no changes required
if (s1[i - 1] === s2[j - 1]) {
DP[i][j] = DP[i - 1][j - 1];
} else {
// minimum of three operations possible
DP[i][j] = Math.min(Math.min(DP[i - 1][j - 1], DP[i - 1][j]), DP[i][j - 1]) + 1;
}
}
}
// print the steps
printChanges(s1, s2, DP);
} // Driver Code let s1 = "abcdef" ;
let s2 = "axcdfdh" ;
// calculate the DP matrix editDP(s1, s2); // This code is contributed by lokeshpotta20. |
change f to h change e to d Add f change b to x
The time complexity of the given implementation of the edit distance algorithm is O(m*n), where m and n are the lengths of the input strings s1 and s2, respectively. This is because the DP matrix is computed in a nested loop that iterates over each position in the matrix exactly once.
The space complexity of the implementation is O(m*n) as well, since the DP matrix is stored in a two-dimensional array of size (m+1) x (n+1). This is because the algorithm needs to store the minimum edit distance values for each prefix of s1 and s2, including the empty string prefixes.
Approach to print all possible ways:
Create a collection of strings that will store the operations required. This collection can be a vector of strings in C++ or a List of strings in Java. Add operations just like printing them before to this collection. Then create a collection of these collections which will store the multiple methods (sets of string operations).
Else-if was used earlier to check from where we derived the DP[i][j] from. Now, check all If’s to see if there were more than 1 ways you could obtain the element. If there was, we create a new collection from before, remove the last operation, add this new operation and initiate another instance of this function with this new list. In this manner, add new lists whenever there was a new method to change str1 to str2, getting a new method every time.
On reaching the end of either string, add this list to the collection of lists, thus completing the set of all possible operations, and add them.
Below is the implementation of the above approach:
using System;
using System.Collections.Generic;
class Program
{ // Create List of lists that will store all sets of operations
static List<List<string>> arrs = new List<List<string>>();
static int [,] dp = new int [1001, 1001];
// Function to print all ways
static void PrintAllChanges(string s1, string s2, List<string> changes)
{
int i = s1.Length;
int j = s2.Length;
// Iterate till the end
while ( true )
{
if (i == 0 || j == 0)
{
// Add this list to our List of lists.
arrs.Add( new List<string>(changes));
break ;
}
// If same
if (s1[i - 1] == s2[j - 1])
{
i--;
j--;
}
else
{
bool if1 = false , if2 = false ;
// Replace
if (dp[i, j] == dp[i - 1, j - 1] + 1)
{
// Add this step
changes.Add( "Change " + s1[i - 1] + " to " + s2[j - 1]);
i--;
j--;
if1 = true ;
}
// Delete
if (dp[i, j] == dp[i - 1, j] + 1)
{
if (!if1)
{
changes.Add( "Delete " + s1[i - 1]);
i--;
}
else
{
// If the previous method was true,
// create a new list as a copy of the previous.
List<string> changes2 = new List<string>(changes);
changes2.RemoveAt(changes2.Count - 1);
// Add this new operation
changes2.Add( "Delete " + s1[i]);
// Initiate a new instance of this function with remaining substrings
PrintAllChanges(s1.Substring(0, i), s2.Substring(0, j + 1), changes2);
}
if2 = true ;
}
// Add character step
if (dp[i, j] == dp[i, j - 1] + 1)
{
if (!if1 && !if2)
{
changes.Add( "Add " + s2[j - 1]);
j--;
}
else
{
// Add steps
List<string> changes2 = new List<string>(changes);
changes2.RemoveAt(changes2.Count - 1);
changes2.Add( "Add " + s2[j]);
// Recursively call for the next steps
PrintAllChanges(s1.Substring(0, i + 1), s2.Substring(0, j), changes2);
}
}
}
}
}
// Function to compute the DP matrix
static void EditDP(string s1, string s2)
{
int l1 = s1.Length;
int l2 = s2.Length;
// Initialize by the maximum edits possible
for ( int i = 0; i <= l1; i++)
dp[i, 0] = i;
for ( int j = 0; j <= l2; j++)
dp[0, j] = j;
// Compute the DP matrix
for ( int i = 1; i <= l1; i++)
{
for ( int j = 1; j <= l2; j++)
{
// If the characters are the same, no changes required
if (s1[i - 1] == s2[j - 1])
dp[i, j] = dp[i - 1, j - 1];
else
// Minimum of three operations possible
dp[i, j] = Math.Min(dp[i - 1, j - 1], Math.Min(dp[i - 1, j], dp[i, j - 1])) + 1;
}
}
}
static void PrintWays(string s1, string s2, List<string> changes)
{
// Function to print all the ways
PrintAllChanges(s1, s2, new List<string>());
int i = 1;
// Print all the possible ways
foreach (var ar in arrs)
{
Console.WriteLine( "\nMethod " + i + " : " );
foreach (var s in ar)
{
Console.WriteLine(s);
}
i++;
}
}
// Driver Code
static void Main()
{
string s1 = "abcdef" ;
string s2 = "axcdfdh" ;
// Calculate the DP matrix
EditDP(s1, s2);
// Function to print all ways
PrintWays(s1, s2, new List<string>());
}
} |
import java.util.*;
class FollowUp_PrintAllPossibleChanges {
int [][] dp;
// List of changes stores all possible ways, each way - list of operations
List<List<String> > allWays = new ArrayList<>();
int minDistance(String s, String targ) {
int m = s.length(), n = targ.length();
dp = new int [m + 1 ][n + 1 ];
// initialize by the maximum edits possible
for ( int i = 0 ; i <= m; i++) dp[i][ 0 ] = i;
for ( int j = 0 ; j <= n; j++) dp[ 0 ][j] = j;
for ( int i = 1 ; i <= m; i++)
for ( int j = 1 ; j <= n; j++)
if (s.charAt(i - 1 ) == targ.charAt(j - 1 )) dp[i][j] = dp[i - 1 ][j - 1 ];
else dp[i][j] = 1 + Math.min(dp[i - 1 ][j - 1 ], Math.min(dp[i - 1 ][j], dp[i][j - 1 ]));
return dp[m][n];
}
void printAllChanges(String s, String t, List<String> changes) {
int i = s.length(), j = t.length();
while (i > 0 && j > 0 ) {
if (s.charAt(i - 1 ) == t.charAt(j - 1 )) { i--; j--; } // Match
else { // Not match:
boolean replaced = false , deleted = false ;
int nextI = i, nextJ = j; // We dont want 1st if influence other ifs
// Don't just pick single way, try all 3 ways if they all minimal
if (dp[i][j] == dp[i - 1 ][j - 1 ] + 1 ) { // Replace
changes.add(s.charAt(i - 1 ) + "->" + t.charAt(j - 1 ));
nextI = i - 1 ; nextJ = j - 1 ; replaced = true ;
}
if (dp[i][j] == dp[i - 1 ][j] + 1 ) { // Delete
if (!replaced) { changes.add( "Del " + s.charAt(i - 1 )); nextI = i - 1 ; } // Reuse 'changes' if only single operation possible
else {
// If also was replaced -> we have at least 2 ways for edit,
// so create new changes(like new path) & remove 'Replace' operation coz here we chosen to 'Delete'
// (Changes should have one of 3 operations, can't replace and remove same char, that doesnt make sense)
var changes2 = new ArrayList<>(changes);
changes2.remove(changes.size() - 1 ); // Remove last operation
changes2.add( "Del " + s.charAt(i - 1 )); // Add this new operation
// initiate new instance of this fun with remaining substrings
printAllChanges(s.substring( 0 , i - 1 ), t.substring( 0 , j), changes2);
}
deleted = true ;
}
if (dp[i][j] == dp[i][j - 1 ] + 1 ) { // Add ch
if (!replaced && !deleted) { changes.add( "Add " + t.charAt(j - 1 )); nextJ = j - 1 ; } // One op only if not Replaced & Deleted
else {
var changes2 = new ArrayList<>(changes);
changes2.remove(changes.size() - 1 );
changes2.add( "Add " + t.charAt(j - 1 ));
printAllChanges(s.substring( 0 , i), t.substring( 0 , j - 1 ), changes2);
}
}
i = nextI; j = nextJ;
}
}
while (i > 0 ) changes.add( "Del " + s.charAt(--i)); // 't' matched but some 's' chars left not removed - rm all 's' chars
while (j > 0 ) changes.add( "Add " + t.charAt(--j)); // 's' chars finished but not all 't' chars matched - add missing
allWays.add(changes);
}
void printWays(String s1, String s2) {
printAllChanges(s1, s2, new ArrayList<>());
int i = 1 ;
for (var way : allWays) {
System.out.print( "Method #" + i++ + ": " );
System.out.println(String.join( ", " , way));
}
}
public static void main(String[] args) throws Exception {
var o = new FollowUp_PrintAllPossibleChanges();
o.minDistance( "abcdef" , "axcdfdh" );
o.printWays( "abcdef" , "axcdfdh" );
// Only add: GeeksForGeeks impl won't print added chars
o = new FollowUp_PrintAllPossibleChanges();
o.minDistance( "" , "abc" );
o.printWays( "" , "abc" );
// Only remove: GeeksForGeeks impl won't print removed chars
o = new FollowUp_PrintAllPossibleChanges();
o.minDistance( "abc" , "" );
o.printWays( "abc" , "" );
}
} |
import numpy as np
# create List of lists that will store all sets of operations arrs = []
# Function to print all ways def printAllChanges(s1, s2, changes):
i = len (s1)
j = len (s2)
# Iterate till end
while True :
if i = = 0 or j = = 0 :
# Add this list to our List of lists.
arrs.append(changes)
break
# If same
if s1[i - 1 ] = = s2[j - 1 ]:
i - = 1
j - = 1
else :
if1 = False
if2 = False
# Replace
if dp[i][j] = = dp[i - 1 ][j - 1 ] + 1 :
# Add this step
changes.append(f "Change {s1[i-1]} to {s2[j-1]}" )
i - = 1
j - = 1
if1 = True
# Delete
if dp[i][j] = = dp[i - 1 ][j] + 1 :
if not if1:
changes.append(f "Delete {s1[i-1]}" )
i - = 1
else :
# If the previous method was true,
# create a new list as a copy of previous.
changes2 = changes.copy()
changes2.pop()
# Add this new operation
changes2.append(f "Delete {s1[i]}" )
# initiate new new instance of this function with remaining substrings
printAllChanges(s1[:i], s2[:j + 1 ], changes2)
if2 = True
# Add character step
if dp[i][j] = = dp[i][j - 1 ] + 1 :
if not if1 and not if2:
changes.append(f "Add {s2[j-1]}" )
j - = 1
else :
# Add steps
changes2 = changes.copy()
changes2.pop()
changes2.append(f "Add {s2[j]}" )
# Recursively call for the next steps
printAllChanges(s1[:i + 1 ], s2[:j], changes2)
# Move to previous subproblem
i - = 1
j - = 1
# Function to compute the DP matrix def editDP(s1, s2):
l1 = len (s1)
l2 = len (s2)
# initialize by the maximum edits possible
dp = np.zeros((l1 + 1 , l2 + 1 ))
for i in range (l1 + 1 ):
dp[i][ 0 ] = i
for j in range (l2 + 1 ):
dp[ 0 ][j] = j
# Compute the DP matrix
for i in range ( 1 , l1 + 1 ):
for j in range ( 1 , l2 + 1 ):
# if the characters are same
# no changes required
if s1[i - 1 ] = = s2[j - 1 ]:
dp[i][j] = dp[i - 1 ][j - 1 ]
else :
# minimum of three operations possible
dp[i][j] = min (dp[i - 1 ][j - 1 ], dp[i - 1 ][j], dp[i][j - 1 ]) + 1
return dp
def printWays(s1, s2, changes):
# Function to print all the ways
printAllChanges(s1, s2, [])
i = 1
# print all the possible ways
for ar in arrs:
print ( "\nMethod {}: " . format (i))
for s in ar:
print (s)
i + = 1
# Driver Code if __name__ = = "__main__" :
s1 = "abcdef"
s2 = "axcdfdh"
# calculate the DP matrix
editDP(s1, s2)
# Function to print all ways
printWays(s1, s2, [])
|
using System;
using System.Collections.Generic;
class Program
{ // Create List of lists that will store all sets of operations
static List<List< string >> arrs = new List<List< string >>();
static int [,] dp = new int [1001, 1001];
// Function to print all ways
static void PrintAllChanges( string s1, string s2, List< string > changes)
{
int i = s1.Length;
int j = s2.Length;
// Iterate till the end
while ( true )
{
if (i == 0 || j == 0)
{
// Add this list to our List of lists.
arrs.Add( new List< string >(changes));
break ;
}
// If same
if (s1[i - 1] == s2[j - 1])
{
i--;
j--;
}
else
{
bool if1 = false , if2 = false ;
// Replace
if (dp[i, j] == dp[i - 1, j - 1] + 1)
{
// Add this step
changes.Add( "Change " + s1[i - 1] + " to " + s2[j - 1]);
i--;
j--;
if1 = true ;
}
// Delete
if (dp[i, j] == dp[i - 1, j] + 1)
{
if (!if1)
{
changes.Add( "Delete " + s1[i - 1]);
i--;
}
else
{
// If the previous method was true,
// create a new list as a copy of the previous.
List< string > changes2 = new List< string >(changes);
changes2.RemoveAt(changes2.Count - 1);
// Add this new operation
changes2.Add( "Delete " + s1[i]);
// Initiate a new instance of this function with remaining substrings
PrintAllChanges(s1.Substring(0, i), s2.Substring(0, j + 1), changes2);
}
if2 = true ;
}
// Add character step
if (dp[i, j] == dp[i, j - 1] + 1)
{
if (!if1 && !if2)
{
changes.Add( "Add " + s2[j - 1]);
j--;
}
else
{
// Add steps
List< string > changes2 = new List< string >(changes);
changes2.RemoveAt(changes2.Count - 1);
changes2.Add( "Add " + s2[j]);
// Recursively call for the next steps
PrintAllChanges(s1.Substring(0, i + 1), s2.Substring(0, j), changes2);
}
}
}
}
}
// Function to compute the DP matrix
static void EditDP( string s1, string s2)
{
int l1 = s1.Length;
int l2 = s2.Length;
// Initialize by the maximum edits possible
for ( int i = 0; i <= l1; i++)
dp[i, 0] = i;
for ( int j = 0; j <= l2; j++)
dp[0, j] = j;
// Compute the DP matrix
for ( int i = 1; i <= l1; i++)
{
for ( int j = 1; j <= l2; j++)
{
// If the characters are the same, no changes required
if (s1[i - 1] == s2[j - 1])
dp[i, j] = dp[i - 1, j - 1];
else
// Minimum of three operations possible
dp[i, j] = Math.Min(dp[i - 1, j - 1], Math.Min(dp[i - 1, j], dp[i, j - 1])) + 1;
}
}
}
static void PrintWays( string s1, string s2, List< string > changes)
{
// Function to print all the ways
PrintAllChanges(s1, s2, new List< string >());
int i = 1;
// Print all the possible ways
foreach ( var ar in arrs)
{
Console.WriteLine( "\nMethod " + i + " : " );
foreach ( var s in ar)
{
Console.WriteLine(s);
}
i++;
}
}
// Driver Code
static void Main()
{
string s1 = "abcdef" ;
string s2 = "axcdfdh" ;
// Calculate the DP matrix
EditDP(s1, s2);
// Function to print all ways
PrintWays(s1, s2, new List< string >());
}
} |
// JavaScript program to print all the possible // steps to change a string to another // create List of lists that will store all sets of // operations let arrs = []; let dp = new Array(1001).fill( null ).map(() => new Array(1001).fill(0));
// Function to print all ways function printAllChanges(s1, s2, changes) {
let i = s1.length;
let j = s2.length;
// Iterate till end
while ( true ) {
if (i === 0 || j === 0) {
// Add this list to our List of lists.
arrs.push(changes.slice());
break ;
}
// If same
if (s1[i - 1] === s2[j - 1]) {
i--;
j--;
} else {
let if1 = false ,
if2 = false ;
// Replace
if (dp[i][j] === dp[i - 1][j - 1] + 1) {
// Add this step
changes.push(`Change ${s1[i - 1]} to ${s2[j - 1]}`);
i--;
j--;
if1 = true ;
}
// Delete
if (dp[i][j] === dp[i - 1][j] + 1) {
if (!if1) {
changes.push(`Delete ${s1[i - 1]}`);
i--;
} else {
// If the previous method was true,
// create a new list as a copy of
// previous.
let changes2 = changes.slice(0, -1);
// Add this new operation
changes2.push(`Delete ${s1[i]}`);
// initiate new new instance of this
// function with remaining substrings
printAllChanges(s1.slice(0, i), s2.slice(0, j + 1), changes2);
}
if2 = true ;
}
// Add character step
if (dp[i][j] === dp[i][j - 1] + 1) {
if (!if1 && !if2) {
changes.push(`Add ${s2[j - 1]}`);
j--;
} else {
// Add steps
let changes2 = changes.slice(0, -1);
changes2.push(`Add ${s2[j]}`);
// Recursively call for the next steps
printAllChanges(s1.slice(0, i + 1), s2.slice(0, j), changes2);
}
}
}
}
} // Function to compute the DP matrix function editDP(s1, s2) {
let l1 = s1.length;
let l2 = s2.length;
// initialize by the maximum edits possible
for (let i = 0; i <= l1; i++) {
dp[i][0] = i;
}
for (let j = 0; j <= l2; j++) {
dp[0][j] = j;
}
// Compute the DP matrix
for (let i = 1; i <= l1; i++) {
for (let j = 1; j <= l2; j++) {
// if the characters are same
// no changes required
if (s1[i - 1] === s2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
// minimum of three operations possible
dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1;
}
}
}
} function printWays(s1, s2, changes) {
// Function to print all the ways
printAllChanges(s1, s2, []);
let i = 1;
// print all the possible ways
for (let ar of arrs) {
console.log(`\nMethod ${i++} : `);
for (let s of ar) {
console.log(s);
}
}
} // Driver Code let s1 = "abcdef" ;
let s2 = "axcdfdh" ;
// calculate the DP matrix editDP(s1, s2); // Function to print all ways printWays(s1, s2, []); // Contributed by adityasharmadev01 |
Method 1 : Add h Change f to d Change e to f Change b to x Method 2 : Change f to h Add d Change e to f Change b to x Method 3 : Change f to h Change e to d Add f Change b to x
Time Complexity: O(m*n*n*k) m – length of s1, n – length of s2, second n caused by fact that we copy ‘changes’ every time there is more than one way found, k – num of all possible ways, upper-bound for k= 3^n
Space Complexity: O(n^2) due to the use of the dp array