Open In App

Transform an Empty String to a Given String

Given a string s1 and an empty string s2, you have to transform the empty string s2 to given string s1 using the given moves. In one move, you can create a sequence of identical characters on string s2 or overwrite any substring with a new character on string s2. The task is to minimize the number of moves to transform string s2 to s1.

Example:



Input: s1 = “aaaddd”, s2 = “”
Output: 2
Explanation: Write “aaa” first and then write “ddd”.

Input: s1 = “aca”, s2 = “”
Output: 2
Explanation: Write “aaa” first and then write “c” from the second place of the string, which will cover the existing character ‘a’.



Approach:

This problem can be simplified by breaking it down into smaller parts using the Divide and Conquer strategy. We continue to divide the string ‘s1’ until we get substrings of 1 or 2 characters, which act as our base case. We create a dynamic programming (DP) table ‘dp’, where dp[i][j] represents the minimum number of operations needed to write the substring from the i-th to the j-th character in ‘s’ (both inclusive).

Base Case: For a single character (a substring of length 1), we only need one operation to write it. Hence, dp[i][i] is set to 1 for all ‘i’.

Recursive Formula: We then find the minimum number of operations for substrings of length 2, 3, and so on, up to the length of the entire string.

For each substring length, we iterate over all possible starting (i) and ending (j) points of that substring. To compute dp[i][j], we iterate over all possible ‘k’ from ‘i’ to ‘j-1’ (inclusive). For each ‘k’, we try to find the minimum number of operations by combining the minimum operations required to write s1[i…k] and s1[k+1…j].

Final Answer: The solution to the problem will be stored in dp[0][n-1], where ‘n’ is the length of the string.

Steps-by-step approach:

Below is the implementation of the above approach:




// C++ code for the above approach:
#include <climits>
#include <iostream>
#include <vector>
 
using namespace std;
 
int minOperation(string s)
{
    int n = s.length();
    vector<vector<int> > dp(n, vector<int>(n, 0));
 
    for (int i = n - 1; i >= 0; --i) {
 
        // Base case: writing one character
        // always takes 1 operation.
        // Example: 'a' -> 1 operation
        dp[i][i] = 1;
 
        for (int j = i + 1; j < n; ++j) {
            dp[i][j] = INT_MAX;
 
            // Iterate through partition points k
            for (int k = i; k < j; ++k) {
 
                // Calculate the minimum operations
                // for writing s[i...k] and s[k+1...j]
                int minOperations = dp[i][k] + dp[k + 1][j];
 
                // If s[i] and s[j] are the same,
                // we need one less turn because
                // we can write both characters
                // in a single operation only.
                if (s[i] == s[j])
                    minOperations--; // Example: 'aabaa' ->
                                    // Operations req: 2
                                    // instead of 3
 
                // Update dp[i][j] with the minimum
                // operations for s[i...j]
                dp[i][j] = min(dp[i][j], minOperations);
            }
        }
    }
 
    // Minimum operation for writing the entire
    // string s[0...n-1]
    return dp[0][n - 1];
}
 
// Drivers code
int main()
{
 
    string S1 = "aabca", S2 = "";
 
    // Function Call
    cout << minOperation(S1);
 
    return 0;
}




public class MinOperation {
 
    // Function to calculate the minimum operations to write the given string
    static int minOperation(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];
 
        // Dynamic Programming loop for bottom-up calculation
        for (int i = n - 1; i >= 0; --i) {
 
            // Base case: writing one character always takes 1 operation.
            // Example: 'a' -> 1 operation
            dp[i][i] = 1;
 
            for (int j = i + 1; j < n; ++j) {
                dp[i][j] = Integer.MAX_VALUE;
 
                // Iterate through partition points k
                for (int k = i; k < j; ++k) {
 
                    // Calculate the minimum operations for writing s[i...k] and s[k+1...j]
                    int minOperations = dp[i][k] + dp[k + 1][j];
 
                    // If s[i] and s[j] are the same, we need one less turn because
                    // we can write both characters in a single operation only.
                    if (s.charAt(i) == s.charAt(j))
                        minOperations--; // Example: 'aabaa' -> Operations req: 2 instead of 3
 
                    // Update dp[i][j] with the minimum operations for s[i...j]
                    dp[i][j] = Math.min(dp[i][j], minOperations);
                }
            }
        }
 
        // Minimum operation for writing the entire string s[0...n-1]
        return dp[0][n - 1];
    }
 
    // Driver code
    public static void main(String[] args) {
        String S1 = "aabca";
 
        // Function Call
        System.out.println(minOperation(S1));
    }
}
 
// This code is contributed by rambabuguphka




def minOperation(s):
    n = len(s)
    dp = [[0] * n for _ in range(n)]
 
    for i in range(n - 1, -1, -1):
        # Base case: writing one character
        # always takes 1 operation.
        # Example: 'a' -> 1 operation
        dp[i][i] = 1
 
        for j in range(i + 1, n):
            dp[i][j] = float('inf')
 
            # Iterate through partition points k
            for k in range(i, j):
 
                # Calculate the minimum operations
                # for writing s[i...k] and s[k+1...j]
                minOperations = dp[i][k] + dp[k + 1][j]
 
                # If s[i] and s[j] are the same,
                # we need one less turn because
                # we can write both characters
                # in a single operation only.
                if s[i] == s[j]:
                    minOperations -= 1  # Example: 'aabaa' ->
                                        # Operations req: 2
                                        # instead of 3
 
                # Update dp[i][j] with the minimum
                # operations for s[i...j]
                dp[i][j] = min(dp[i][j], minOperations)
 
    # Minimum operation for writing the entire
    # string s[0...n-1]
    return dp[0][n - 1]
 
# Drivers code
if __name__ == "__main__":
    S1 = "aabca"
 
    # Function Call
    print(minOperation(S1))




using System;
 
public class MinOperation {
    // Function to calculate the minimum operations to write
    // the given string
    static int CalculateMinOperation(string s)
    {
        int n = s.Length;
        int[, ] dp = new int[n, n];
 
        // Dynamic Programming loop for bottom-up
        // calculation
        for (int i = n - 1; i >= 0; --i) {
            // Base case: writing one character always takes
            // 1 operation. Example: 'a' -> 1 operation
            dp[i, i] = 1;
 
            for (int j = i + 1; j < n; ++j) {
                dp[i, j] = int.MaxValue;
 
                // Iterate through partition points k
                for (int k = i; k < j; ++k) {
                    // Calculate the minimum operations for
                    // writing s[i...k] and s[k+1...j]
                    int minOperations
                        = dp[i, k] + dp[k + 1, j];
 
                    // If s[i] and s[j] are the same, we
                    // need one less turn because we can
                    // write both characters in a single
                    // operation only.
                    if (s[i] == s[j])
                        minOperations--; // Example: 'aabaa'
                                         // -> Operations
                                         // req: 2 instead
                                         // of 3
 
                    // Update dp[i, j] with the minimum
                    // operations for s[i...j]
                    dp[i, j]
                        = Math.Min(dp[i, j], minOperations);
                }
            }
        }
 
        // Minimum operation for writing the entire string
        // s[0...n-1]
        return dp[0, n - 1];
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        string S1 = "aabca";
 
        // Function Call
        Console.WriteLine(CalculateMinOperation(S1));
    }
}




function minOperation(s) {
    const n = s.length;
    const dp = Array.from({ length: n }, () => Array(n).fill(0));
 
    for (let i = n - 1; i >= 0; i--) {
        dp[i][i] = 1;
 
        for (let j = i + 1; j < n; j++) {
            dp[i][j] = Infinity;
 
            for (let k = i; k < j; k++) {
                let minOperations = dp[i][k] + dp[k + 1][j];
 
                if (s[i] === s[j]) {
                    minOperations--; // Example: 'aabaa' -> Operations req: 2 instead of 3
                }
 
                dp[i][j] = Math.min(dp[i][j], minOperations);
            }
        }
    }
 
    // Minimum operation for writing the entire string s[0...n-1]
    return dp[0][n - 1];
}
 
// Driver code
const S1 = "aabca";
 
// Function Call
console.log(minOperation(S1));

Output
3





Time Complexity: O(n^3), where n is length of given string.
Auxiliary Space: O(n*n)


Article Tags :