Open In App

Transform an Empty String to a Given String

Last Updated : 05 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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:

  • Set n to the length of the string s1 and create a 2D vector dp of size n x n, initialized with zeros.
  • Iterate from the end of the string to the beginning (from n-1 to 0).
    • For each character at position i, set dp[i][i] to 1 as a base case.
    • For each position i, iterate from i+1 to n-1 (inclusive).
    • Initialize dp[i][j] to INT_MAX.
    • Iterate through partition points k from i to j.
      • Calculate the minimum operations for writing s1[i…k] and s1[k+1…j].
      • If s1[i] and s1[j] are the same, decrement minOperations by 1.
      • Update dp[i][j] with the minimum operations for writing s1[i…j].
  • Return dp[0][n – 1], representing the minimum operations needed to write the entire string s1[0…n-1].

Below is the implementation of the above approach:

C++




// 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;
}


Java




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


Python




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))


C#




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));
    }
}


Javascript




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)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads