Given two Strings S and T of length N consisting of lowercase alphabets, which are permutations of each other, the task is to print the minimum number of operations to convert S to T. In one operation, pick any character of the string S and move it either to the start or end of the string S.
Examples:
Input: S = “abcde”, T = “edacb”
Output: 3
Explanation:
We can convert S to T in 3 moves:
1. move ‘d’ to start: “dabce”
2. move ‘e’ to start: “edabc”
3. move ‘b’ to end: “edacb”
Input: S = “dcdb”, T = “ddbc”
Output: 1
Explanation:
Move ‘c’ to end
Naive Approach: The naive approach is to try all possibilities of swapping a character. One can put some character to the front, to the end, or can leave it in the same position. The above three operations can be solved using recursion and print the minimum number of steps required after all the steps.
Time Complexity: O(3N), where N is the length of the given string.
Auxiliary Space: O(1)
Efficient Approach: To optimize the above approach, the idea is to observe that after moving the characters of the string S, the unchanged characters come together to form a contiguous substring in T. So, if we can maximize the length of this subsequence, then the count of operations to convert string S to T is:
N – length of the longest contiguous substring of T that is a subsequence of S
Therefore, to find the length of the longest contiguous substring of T that is a subsequence of string S, find the longest common subsequence of S and T. Let dp[][] stores the length of the longest contiguous substring of T that is a subsequence of string S, . Now dp[i][j] will store the length of the longest suffix of T[0, …, j] that is also a subsequence of S[0, …, i]. The recurrence relation is given by:
- If i is greater than 0, dp[i][j] = max(dp[i-1][j], dp[i][j]).
- If S[i] is equals to T[i] then, dp[i][j] = 1 + dp[i-1][j-1].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[1010][1010];
int solve(string s, string t)
{
int n = s.size();
int r = 0;
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < n; j++) {
dp[i][j] = 0;
if (i > 0) {
dp[i][j] = max(dp[i - 1][j],
dp[i][j]);
}
if (s[i] == t[j]) {
int ans = 1;
if (i > 0 && j > 0) {
ans = 1 + dp[i - 1][j - 1];
}
dp[i][j] = max(dp[i][j], ans);
r = max(r, dp[i][j]);
}
}
}
return (n - r);
}
int main()
{
string s = "abcde" ;
string t = "edacb" ;
cout << solve(s, t);
return 0;
}
|
Java
class GFG{
static int [][] dp = new int [ 1010 ][ 1010 ];
static int solve(String s, String t)
{
int n = s.length();
int r = 0 ;
for ( int i = 0 ; i < n; i++)
{
for ( int j = 0 ; j < n; j++)
{
dp[i][j] = 0 ;
if (i > 0 )
{
dp[i][j] = Math.max(dp[i - 1 ][j],
dp[i][j]);
}
if (s.charAt(i) == t.charAt(j))
{
int ans = 1 ;
if (i > 0 && j > 0 )
{
ans = 1 + dp[i - 1 ][j - 1 ];
}
dp[i][j] = Math.max(dp[i][j], ans);
r = Math.max(r, dp[i][j]);
}
}
}
return (n - r);
}
public static void main(String[] args)
{
String s = "abcde" ;
String t = "edacb" ;
System.out.print(solve(s, t));
}
}
|
Python3
dp = [[ 0 ] * 1010 ] * 1010
def solve(s, t):
n = len (s)
r = 0
for j in range ( 0 , n):
for i in range ( 0 , n):
dp[i][j] = 0
if (i > 0 ):
dp[i][j] = max (dp[i - 1 ][j],
dp[i][j])
if (s[i] = = t[j]):
ans = 1
if (i > 0 and j > 0 ):
ans = 1 + dp[i - 1 ][j - 1 ]
dp[i][j] = max (dp[i][j], ans)
r = max (r, dp[i][j])
return (n - r)
s = "abcde"
t = "edacb"
print (solve(s, t))
|
C#
using System;
class GFG{
static int [, ] dp = new int [1010, 1010];
static int solve(String s, String t)
{
int n = s.Length;
int r = 0;
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < n; j++)
{
dp[i, j] = 0;
if (i > 0)
{
dp[i, j] = Math.Max(dp[i - 1, j],
dp[i, j]);
}
if (s[i] == t[j])
{
int ans = 1;
if (i > 0 && j > 0)
{
ans = 1 + dp[i - 1, j - 1];
}
dp[i, j] = Math.Max(dp[i, j], ans);
r = Math.Max(r, dp[i, j]);
}
}
}
return (n - r);
}
public static void Main(String[] args)
{
String s = "abcde" ;
String t = "edacb" ;
Console.Write(solve(s, t));
}
}
|
Javascript
<script>
var dp = Array.from(Array(1010), ()=> Array(1010));
function solve(s, t)
{
var n = s.length;
var r = 0;
for ( var i = 0; i < n; i++) {
for ( var j = 0; j < n; j++) {
dp[i][j] = 0;
if (i > 0) {
dp[i][j] = Math.max(dp[i - 1][j],
dp[i][j]);
}
if (s[i] == t[j]) {
var ans = 1;
if (i > 0 && j > 0) {
ans = 1 + dp[i - 1][j - 1];
}
dp[i][j] = Math.max(dp[i][j], ans);
r = Math.max(r, dp[i][j]);
}
}
}
return (n - r);
}
var s = "abcde" ;
var t = "edacb" ;
document.write( solve(s, t));
</script>
|
Time Complexity: O(N2), where N is the length of the given string
Auxiliary Space: O(N2)
Efficient approach : Space optimization using 2 vectors
In this approach we use two vectors because in previous approach we can see that dp[i][j] is only dependent on the current row and previous row of dp.
dp[i][j] = max(dp[i – 1][j], dp[i][j]);
Implementation Steps :
- Made 2 vectors says curr and prev that use to keep track of values of current and previous row of matrix respectively.
- Now change dp[i] to curr and dp[i-1] to prev in previous approach.
- After every iteration of outer loop store all values of curr to prev and move to the next iterations
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
int solve(string s, string t)
{
int n = s.size();
vector< int >prev(n+1);
vector< int >curr(n+1);
int r = 0;
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < n; j++) {
curr[j] = 0;
if (i > 0) {
curr[j] = max(prev[j], curr[j]);
}
if (s[i] == t[j]) {
int ans = 1;
if (i > 0 && j > 0) {
ans = 1 + prev[j - 1];
}
curr[j] = max(curr[j], ans);
r = max(r, curr[j]);
}
}
prev = curr;
}
return (n - r);
}
int main()
{
string s = "abcde" ;
string t = "edacb" ;
cout << solve(s, t);
return 0;
}
|
Java
import java.util.*;
public class Main {
static int solve(String s, String t) {
int n = s.length();
int [] prev = new int [n+ 1 ];
int [] curr = new int [n+ 1 ];
int r = 0 ;
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j < n; j++) {
curr[j] = 0 ;
if (i > 0 ) {
curr[j] = Math.max(prev[j], curr[j]);
}
if (s.charAt(i) == t.charAt(j)) {
int ans = 1 ;
if (i > 0 && j > 0 ) {
ans = 1 + prev[j - 1 ];
}
curr[j] = Math.max(curr[j], ans);
r = Math.max(r, curr[j]);
}
}
prev = curr.clone();
}
return (n - r);
}
public static void main(String[] args) {
String s = "abcde" ;
String t = "edacb" ;
System.out.println(solve(s, t));
}
}
|
Python3
def solve(s, t):
n = len (s)
prev = [ 0 ] * (n + 1 )
curr = [ 0 ] * (n + 1 )
r = 0
for i in range (n):
for j in range (n):
curr[j] = 0
if i > 0 :
curr[j] = max (prev[j], curr[j])
if s[i] = = t[j]:
ans = 1
if i > 0 and j > 0 :
ans = 1 + prev[j - 1 ]
curr[j] = max (curr[j], ans)
r = max (r, curr[j])
prev = curr[:]
return (n - r)
if __name__ = = '__main__' :
s = "abcde"
t = "edacb"
print (solve(s, t))
|
C#
using System;
public class MainClass {
static int Solve( string s, string t)
{
int n = s.Length;
int [] prev = new int [n + 1];
int [] curr = new int [n + 1];
int r = 0;
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < n; j++) {
curr[j] = 0;
if (i > 0) {
curr[j] = Math.Max(prev[j], curr[j]);
}
if (s[i] == t[j]) {
int ans = 1;
if (i > 0 && j > 0) {
ans = 1 + prev[j - 1];
}
curr[j] = Math.Max(curr[j], ans);
r = Math.Max(r, curr[j]);
}
}
prev = ( int [])curr.Clone();
}
return (n - r);
}
public static void Main( string [] args)
{
string s = "abcde" ;
string t = "edacb" ;
Console.WriteLine(Solve(s, t));
}
}
|
Javascript
function solve(s, t) {
const n = s.length;
let prev = new Array(n + 1).fill(0);
let curr = new Array(n + 1).fill(0);
let r = 0;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
curr[j] = 0;
if (i > 0) {
curr[j] = Math.max(prev[j], curr[j]);
}
if (s.charAt(i) == t.charAt(j)) {
let ans = 1;
if (i > 0 && j > 0) {
ans = 1 + prev[j - 1];
}
curr[j] = Math.max(curr[j], ans);
r = Math.max(r, curr[j]);
}
}
prev = curr.slice();
}
return n - r;
}
const s = "abcde" ;
const t = "edacb" ;
console.log(solve(s, t));
|
Time Complexity: O(N2), where N is the length of the given string
Auxiliary Space: O(N) only use 1d vector not 2d matrix to store values.
Note: The above naive approach is efficient for smaller strings whereas, the above efficient approach is efficient for larger strings.