Open In App

Minimize the size of the string formed by performing following operation

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

Given array of strings arr[] of size N. Task for this problem is minimize the size of N’th string formed by performing concatenation operation. If we concat string a and string b to get concat(a, b) then while concatenation if the last character of a is same as first character of b then delete either last character of a or first character of b then concatenate them. Initially we have string S1 = arr1 then:

  • First type of operation Si = concat(Si – 1, arri)
  • Second type of operation, Si = concat(Ai , arri – 1 ) . minimize the size of final string SN and print the size.

Examples:

Input: arr[] = {“aa”, “ab”, “bc”}, N = 3
Output: 4
Explanation: initially we have S[1] = “aa”

  • S[2] = concat(S[1], arr[2]) = “aa” + “ab” = “aab” (since last character of S[1] is same as first character of arr[2] we will delete either last character of S[1] or first character of arr[2]).
  • S[3] = concat(S[2], arr[3]) = “aab” + “bc” = “aabc” (since last character of S[2] is same as first character of arr[3] we will delete either last character of S[2] or first character of arr[3])

so, S[3] = “aabc” minimum size of Nth string is 4

Input: arr[] = {“ba”, “b”}, N = 2
Output: 2
Explanation: initially we have S[1] = “ba”

  • S[2] = concat(arr[2], S[1]) = “b” + “ba” = “ba” (since last character of arr[2] is same as first character of S[1] we will delete either last character of arr[2] or first character of S[1])

so S[2] = “ba” minimum size of Nth string is 2

Top-Down Approach: To solve the problem, follow the below idea:

We will make recursion call for performing both type of operations.

recurrence relation:

  • recur(i, j, k) = min(recur(i + 1, j, arr[i].back()) + arr[i].size() – (k == arr[i][0]), recur(i + 1, curFirst, k) + arr[i].size() – (j == arr[i].back()))
  • recur(i + 1, j, arr[i].back()) + arr[i].size() – (k == arr[i][0]) this recursion call is for performing first type of operation for concatenating strings. First string (which is S[i – 1]) has first and last element as j and k. Second string has first and last element as arr[i][0] and arr[i].back().
  • recur(i + 1, curFirst, k) + arr[i].size() – (j == arr[i].back()) this recursion call is for performing second type of operation for concatenating strings.

Step-by-step algorithm:

  • Declare array dp[1001][26][26]
  • Declare recursive function with three parameters i as index of array arr[], j as first character of S[i – 1] and k as last character of S[i – 1]
    • set base case if i is equal to N return 0
    • if current state is already calculated meaning dp[i][j][k] is not equal to -1 then simply return dp[i][j][k]
    • Declare variable ans with value initialized with 1e9
    • Declare variables curFirst and curLast which holds first and last character of i’th string of array arr[]
    • Declare variable sizeOfithString initialized with value arr[i].size()
    • Make a function call for performing first type of operation
      • Update ans as min(ans, recur(i + 1, j, curLast, arr, N) + sizeOfithString – (int)(k == curFirst))
    • Make a function call for performing second type of operation
      • Update ans as min(ans, recur(i + 1, curFirst, k, arr, N) + sizeOfithString – (int)(j == curLast))
    • return and save ans in dp[i][j][k]
  • Initialize dp array with -1
  • Declare variable ans which stores answer returned by function call which is minimum size of string by performing given operations.
  • return ans

Below is the implementation of the algorithm:

C++
// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;

// mod number
const int mod = 1e9 + 7;

// to avoid interger overflow
#define int long long

// Declaring DP array
int dp[1001][26][26];

// recursive function to Minimize the size of the string
// formed by performing following operation
int recur(int i, int j, int k, vector<string>& A, int N)
{

    // base case
    if (i == N)
        return 0;

    // if current state is already calculated simply
    // return calculated answer
    if (dp[i][j][k] != -1)
        return dp[i][j][k];

    // Declaring anwer variable with value infinity
    int ans = 1e9;

    // i'th strings first and last character
    int curFirst = A[i][0] - 'a',
        curLast = A[i].back() - 'a';

    // size of i'th string
    int sizeOfithString = A[i].size();

    // performing first type of operation (j, k) +
    // (curFirst, curLast)
    ans = min(ans, recur(i + 1, j, curLast, A, N)
                    + sizeOfithString
                    - (int)(k == curFirst));

    // performing second type of operation
    ans = min(ans, recur(i + 1, curFirst, k, A, N)
                    + sizeOfithString
                    - (int)(j == curLast));

    // return and save ans in dp[i][j][k]
    return dp[i][j][k] = ans;
}

// Function to Minimize the size of the string formed by
// performing following operation
int minimizeSizeOfString(vector<string>& A, int N)
{

    // initializing DP array with -1
    memset(dp, -1, sizeof(dp));

    // Declaring ans variable which will make function
    // for finding string with minimum size by performing
    // given operations
    int ans
        = recur(1, A[0][0] - 'a', A[0].back() - 'a', A, N)
        + A[0].size();

    // returning answer
    return ans;
}
// Driver Code
int32_t main()
{

    // Input
    int N = 3;
    vector<string> A{ "aa", "ab", "bc" };

    // Function Call
    cout << minimizeSizeOfString(A, N) << endl;

    return 0;
}
Java
import java.util.Arrays;
import java.util.Vector;

public class Main {

    // mod number
    final static int mod = 1000000007;

    // Declaring DP array
    static int[][][] dp;

    // Function to Minimize the size of the string formed by
    // performing following operation
    static int minimizeSizeOfString(Vector<String> A, int N) {
        // initializing DP array with -1
        dp = new int[1001][26][26];
        for (int i = 0; i < 1001; i++) {
            for (int j = 0; j < 26; j++) {
                Arrays.fill(dp[i][j], -1);
            }
        }

        // Declaring ans variable which will make function
        // for finding string with minimum size by performing
        // given operations
        int ans = recur(1, A.get(0).charAt(0) - 'a', A.get(0).charAt(A.get(0).length() - 1) - 'a', A, N)
                + A.get(0).length();

        // returning answer
        return ans;
    }

    // recursive function to Minimize the size of the string
    // formed by performing following operation
    static int recur(int i, int j, int k, Vector<String> A, int N) {
        // base case
        if (i == N)
            return 0;

        // if current state is already calculated simply
        // return calculated answer
        if (dp[i][j][k] != -1)
            return dp[i][j][k];

        // Declaring anwer variable with value infinity
        int ans = Integer.MAX_VALUE;

        // i'th strings first and last character
        int curFirst = A.get(i).charAt(0) - 'a';
        int curLast = A.get(i).charAt(A.get(i).length() - 1) - 'a';

        // size of i'th string
        int sizeOfithString = A.get(i).length();

        // performing first type of operation (j, k) +
        // (curFirst, curLast)
        ans = Math.min(ans, recur(i + 1, j, curLast, A, N)
                + sizeOfithString - ((k == curFirst) ? 1 : 0));

        // performing second type of operation
        ans = Math.min(ans, recur(i + 1, curFirst, k, A, N)
                + sizeOfithString - ((j == curLast) ? 1 : 0));

        // return and save ans in dp[i][j][k]
        return dp[i][j][k] = ans;
    }

    // Driver Code
    public static void main(String[] args) {
        // Input
        int N = 3;
        Vector<String> A = new Vector<>();
        A.add("aa");
        A.add("ab");
        A.add("bc");

        // Function Call
        System.out.println(minimizeSizeOfString(A, N));
    }
}
//This code is contribuited by Adarsh
Python
# mod number
mod = 10**9 + 7

# Declaring DP array
dp = [[[-1 for _ in range(26)] for _ in range(26)] for _ in range(1001)]

# recursive function to minimize the size of the string
def recur(i, j, k, A, N):
    # base case
    if i == N:
        return 0

    # if current state is already calculated, simply
    # return calculated answer
    if dp[i][j][k] != -1:
        return dp[i][j][k]

    # Declaring answer variable with value infinity
    ans = float('inf')

    # i'th string's first and last character
    curFirst = ord(A[i][0]) - ord('a')
    curLast = ord(A[i][-1]) - ord('a')

    # size of i'th string
    sizeOfithString = len(A[i])

    # performing the first type of operation (j, k) +
    # (curFirst, curLast)
    ans = min(ans, recur(i + 1, j, curLast, A, N)
                  + sizeOfithString
                  - int(k == curFirst))

    # performing the second type of operation
    ans = min(ans, recur(i + 1, curFirst, k, A, N)
                  + sizeOfithString
                  - int(j == curLast))

    # return and save ans in dp[i][j][k]
    dp[i][j][k] = ans
    return ans

# Function to minimize the size of the string formed by
# performing following operation
def minimizeSizeOfString(A, N):
    # initializing DP array with -1
    for i in range(1001):
        for j in range(26):
            for k in range(26):
                dp[i][j][k] = -1

    # Declaring ans variable which will make function
    # for finding string with minimum size by performing
    # given operations
    ans = recur(1, ord(A[0][0]) - ord('a'), ord(A[0][-1]) - ord('a'), A, N) + len(A[0])

    # returning answer
    return ans

# Driver Code
if __name__ == "__main__":
    # Input
    N = 3
    A = ["aa", "ab", "bc"]

    # Function Call
    print(minimizeSizeOfString(A, N))
C#
using System;

class MainClass {
    // mod number
    const int mod = 1000000007;

    // recursive function to minimize the size of the string
    // formed by performing the given operation
    static int Recur(int i, int j, int k, string[] A, int N,
                     int[][][] dp)
    {
        // base case
        if (i == N)
            return 0;

        // if current state is already calculated, simply
        // return the calculated answer
        if (dp[i][j][k] != -1)
            return dp[i][j][k];

        // declaring answer variable with value infinity
        int ans = int.MaxValue;

        // i'th strings first and last character
        int curFirst = A[i][0] - 'a';
        int curLast = A[i][A[i].Length - 1] - 'a';

        // size of i'th string
        int sizeOfithString = A[i].Length;

        // performing first type of operation (j, k) +
        // (curFirst, curLast)
        ans = Math.Min(ans,
                       Recur(i + 1, j, curLast, A, N, dp)
                           + sizeOfithString
                           - (k == curFirst ? 1 : 0));

        // performing second type of operation
        ans = Math.Min(ans,
                       Recur(i + 1, curFirst, k, A, N, dp)
                           + sizeOfithString
                           - (j == curLast ? 1 : 0));

        // return and save ans in dp[i][j][k]
        return dp[i][j][k] = ans;
    }

    // Function to minimize the size of the string formed by
    // performing the given operation
    static int MinimizeSizeOfString(string[] A, int N)
    {
        // initializing DP array with -1
        int[][][] dp = new int[1001][][];
        for (int i = 0; i < 1001; i++) {
            dp[i] = new int[26][];
            for (int j = 0; j < 26; j++) {
                dp[i][j] = new int[26];
                for (int k = 0; k < 26; k++) {
                    dp[i][j][k] = -1;
                }
            }
        }

        // declaring ans variable which will make function
        // for finding string with minimum size by
        // performing given operations
        int ans
            = Recur(1, A[0][0] - 'a',
                    A[0][A[0].Length - 1] - 'a', A, N, dp)
              + A[0].Length;

        // returning answer
        return ans;
    }

    // Driver Code
    public static void Main(string[] args)
    {
        // Input
        int N = 3;
        string[] A = { "aa", "ab", "bc" };

        // Function Call
        Console.WriteLine(MinimizeSizeOfString(A, N));
    }
}
JavaScript
// Function to minimize the size of the string formed by performing the given operation
function minimizeSizeOfString(A, N) {
    // Mod number
    const mod = 1000000007;
    
    // Initializing DP array with -1
    const dp = new Array(1001).fill(null).map(() => new Array(26).fill(null).map(() => new Array(26).fill(-1)));
    
    // Recursive function to minimize the size of the string
    function recur(i, j, k, A, N) {
        // Base case
        if (i === N)
            return 0;

        // If current state is already calculated, simply return the calculated answer
        if (dp[i][j][k] !== -1)
            return dp[i][j][k];

        // Declaring answer variable with value infinity
        let ans = Infinity;

        // i'th string's first and last character
        const curFirst = A[i].charCodeAt(0) - 97;
        const curLast = A[i].charCodeAt(A[i].length - 1) - 97;

        // Size of i'th string
        const sizeOfithString = A[i].length;

        // Performing first type of operation: (j, k) + (curFirst, curLast)
        ans = Math.min(ans, recur(i + 1, j, curLast, A, N) + sizeOfithString - (k === curFirst ? 1 : 0));

        // Performing second type of operation
        ans = Math.min(ans, recur(i + 1, curFirst, k, A, N) + sizeOfithString - (j === curLast ? 1 : 0));

        // Return and save ans in dp[i][j][k]
        return dp[i][j][k] = ans;
    }

    // Call the recursive function with initial values
    return recur(1, A[0].charCodeAt(0) - 97, A[0].charCodeAt(A[0].length - 1) - 97, A, N) + A[0].length;
}

// Driver Code
function main() {
    // Input
    const N = 3;
    const A = ["aa", "ab", "bc"];

    // Function Call
    console.log(minimizeSizeOfString(A, N));
}

// Calling the main function to execute the code
main();

Output
4

Time Complexity: O(N * 26 * 26)
Auxiliary Space: O(N * 26 * 26 )

Bottom up Approach: Implement the idea below to solve the problem

Dynamic Programming can be used to solve this problem. The main concept of DP in the problem will be:
DP[i][j][k] will store minimum size of i’th string with first character it has is j and last character it has is k.

Transition:

  • DP[i][j][A[i].back()] = DP[i – 1][j][k] + arr[i].size() – (k == arr[i][0]) ( we have two strings, string S[i – 1] with first and last character as (j, k) and string arr[i] with first and last character (arr[i][0], arr[i].back()) we will concatenate these two to form string with first and last characters as (j, A[i].back()). This is first type of operation S[i] = concat(S[i – 1], arr[i]))
  • DP[i][A[i][0]][k] = DP[i – 1][j][k] + arr[i].size() – (arr[i].back() == j) ( we have two strings, string S[i – 1] with first and last character as (j, k) and string arr[i] with first and last character (arr[i][0], arr[i].back()) we will concatenate these two to form string with first and last characters as (arr[i][0], k). This is second type of operation S[i] = concat(arr[i], S[i – 1])

Steps were taken to solve the problem:

  • Declaring DP[N + 1][26][26] array
  • Set base case as DP[0][firstCharacterOfA[0]][lastCharacterOfarr[0]] = arr[0].size()
  • Iterate i from 1 to N – 1 and for each i follow steps given:
    • Iterate j from 0 to 25 and for each j follow given steps:
      • Iterate k from 0 to 25 and for each k follow given steps:
        • update DP table according to transitions.
  • Declare variable ans which is set to infinity
  • Iterate i from 0 to 25 and for each i follow given steps:
    • Iterate j from 0 to 25 and for each j follow given steps:
      • update ans as min(ans, DP[N – 1][i][j])
  • return ans

Below is the implementation of the above algorithm:

C++
// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;

// mod number
const int mod = 1e9 + 7;

// to avoid interger overflow
#define int long long

// Function to Minimize the size of the string formed by
// performing following operation
int minimizeSizeOfString(vector<string>& A, int N)
{

    // Declare dp array
    vector<vector<vector<int> > > dp(
        N + 1,
        vector<vector<int> >(26, vector<int>(26, 1e9)));

    // base case
    dp[0][A[0][0] - 'a'][A[0].back() - 'a'] = A[0].size();

    // calculate minimum size of string for i'th operation
    for (int i = 1; i < N; i++) {

        // iterating for all first character j
        for (int j = 0; j < 26; j++) {

            // itearting for all last character k
            for (int k = 0; k < 26; k++) {

                // transition 1: concatenate string with
                // first and last character (j, k) wih
                // string A[i] (whose first and last
                // characters are A[i][0] and A[i].back())
                dp[i][j][A[i].back() - 'a'] = min(
                    dp[i][j][A[i].back() - 'a'],
                    dp[i - 1][j][k] + (int)A[i].size()
                        - (int)(k == (A[i][0] - 'a')));

                // transition 2: concatenate string A[i]
                // (whose first and last characters are
                // A[i][0] and A[i].back()) with string
                // with first and last character (j, k)
                dp[i][A[i][0] - 'a'][k] = min(
                    dp[i][A[i][0] - 'a'][k],
                    dp[i - 1][j][k] + (int)A[i].size()
                        - (int)((A[i].back() - 'a') == j));
            }
        }
    }

    // lets find minimum size of N'th string
    // for all possible i and j
    int ans = INT_MAX;
    for (int i = 0; i < 26; i++) {
        for (int j = 0; j < 26; j++) {
            ans = min(ans, dp[N - 1][i][j]);
        }
    }
    return ans;
}
// Driver Code
int32_t main()
{

    // Input
    int N = 3;
    vector<string> A{ "aa", "ab", "bc" };

    // Function Call
    cout << minimizeSizeOfString(A, N) << endl;

    return 0;
}
Java
import java.util.Arrays;

public class Main {
    // Function to minimize the size of the string formed by
    // performing following operation
    static int minimizeSizeOfString(String[] A, int N) {
        // Declare dp array
        int[][][] dp = new int[N + 1][26][26];

        // Initialize dp array with a large value
        for (int[][] arr2D : dp) {
            for (int[] arr1D : arr2D) {
                Arrays.fill(arr1D, Integer.MAX_VALUE);
            }
        }

        // base case
        dp[0][A[0].charAt(0) - 'a'][A[0].charAt(A[0].length() - 1) - 'a'] = A[0].length();

        // calculate minimum size of string for i'th operation
        for (int i = 1; i < N; i++) {
            // iterating for all first characters j
            for (int j = 0; j < 26; j++) {
                // iterating for all last characters k
                for (int k = 0; k < 26; k++) {
                    // transition 1: concatenate string with
                    // first and last character (j, k) with
                    // string A[i] (whose first and last
                    // characters are A[i].charAt(0) and A[i].charAt(A[i].length() - 1))
                    if (dp[i - 1][j][k] != Integer.MAX_VALUE) {
                        dp[i][j][A[i].charAt(A[i].length() - 1) - 'a'] = Math.min(
                                dp[i][j][A[i].charAt(A[i].length() - 1) - 'a'],
                                dp[i - 1][j][k] + A[i].length()
                                        - ((k == (A[i].charAt(0) - 'a')) ? 1 : 0));
                    }

                    // transition 2: concatenate string A[i]
                    // (whose first and last characters are
                    // A[i].charAt(0) and A[i].charAt(A[i].length() - 1)) with string
                    // with first and last character (j, k)
                    if (dp[i - 1][j][k] != Integer.MAX_VALUE) {
                        dp[i][A[i].charAt(0) - 'a'][k] = Math.min(
                                dp[i][A[i].charAt(0) - 'a'][k],
                                dp[i - 1][j][k] + A[i].length()
                                        - ((A[i].charAt(A[i].length() - 1) - 'a') == j ? 1 : 0));
                    }
                }
            }
        }

        // lets find minimum size of N'th string
        // for all possible i and j
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < 26; i++) {
            for (int j = 0; j < 26; j++) {
                ans = Math.min(ans, dp[N - 1][i][j]);
            }
        }
        return ans;
    }

    // Driver Code
    public static void main(String[] args) {
        // Input
        int N = 3;
        String[] A = { "aa", "ab", "bc" };

        // Function Call
        System.out.println(minimizeSizeOfString(A, N)); // Output should be 4
    }
}
//This code is contributed by Kishan.
Python
# Python code to implement the approach

# Function to minimize the size of the string formed by
# performing the following operation


def minimize_size_of_string(A, N):

    # mod number
    mod = 10**9 + 7

    # to avoid integer overflow
    INT_MAX = float('inf')

    # Declare dp array
    dp = [[[INT_MAX for _ in range(26)] for _ in range(26)]
          for _ in range(N + 1)]

    # base case
    dp[0][ord(A[0][0]) - ord('a')][ord(A[0][-1]) - ord('a')] = len(A[0])

    # calculate the minimum size of string for i'th operation
    for i in range(1, N):

        # iterating for all first character j
        for j in range(26):

            # iterating for all last character k
            for k in range(26):

                # transition 1: concatenate string with
                # first and last character (j, k) with
                # string A[i] (whose first and last
                # characters are A[i][0] and A[i][-1])
                dp[i][j][ord(A[i][-1]) - ord('a')] = min(
                    dp[i][j][ord(A[i][-1]) - ord('a')],
                    dp[i - 1][j][k] + len(A[i])
                    - int(k == (ord(A[i][0]) - ord('a')))
                )

                # transition 2: concatenate string A[i]
                # (whose first and last characters are
                # A[i][0] and A[i][-1]) with string
                # with first and last character (j, k)
                dp[i][ord(A[i][0]) - ord('a')][k] = min(
                    dp[i][ord(A[i][0]) - ord('a')][k],
                    dp[i - 1][j][k] + len(A[i])
                    - int((ord(A[i][-1]) - ord('a')) == j)
                )

    # lets find the minimum size of N'th string
    # for all possible i and j
    ans = INT_MAX
    for i in range(26):
        for j in range(26):
            ans = min(ans, dp[N - 1][i][j])

    return ans


# Driver Code
if __name__ == "__main__":

    # Input
    N = 3
    A = ["aa", "ab", "bc"]

    # Function Call
    print(minimize_size_of_string(A, N))
JavaScript
// Function to minimize the size of the string formed by performing following operation
function minimizeSizeOfString(A, N) {
    // Declare dp array
    const dp = new Array(N + 1).fill(null).map(() => new Array(26).fill(null).map(() => new Array(26).fill(Number.MAX_VALUE)));

    // base case
    dp[0][A[0].charCodeAt(0) - 97][A[0].charCodeAt(A[0].length - 1) - 97] = A[0].length;

    // calculate minimum size of string for i'th operation
    for (let i = 1; i < N; i++) {
        // iterating for all first characters j
        for (let j = 0; j < 26; j++) {
            // iterating for all last characters k
            for (let k = 0; k < 26; k++) {
                // transition 1: concatenate string with first and last character (j, k)
                // with string A[i] (whose first and last characters are A[i].charAt(0) and A[i].charAt(A[i].length - 1))
                if (dp[i - 1][j][k] !== Number.MAX_VALUE) {
                    dp[i][j][A[i].charCodeAt(A[i].length - 1) - 97] = Math.min(
                        dp[i][j][A[i].charCodeAt(A[i].length - 1) - 97],
                        dp[i - 1][j][k] + A[i].length - ((k === (A[i].charCodeAt(0) - 97)) ? 1 : 0)
                    );
                }

                // transition 2: concatenate string A[i] (whose first and last characters are A[i].charAt(0) and A[i].charAt(A[i].length - 1))
                // with string with first and last character (j, k)
                if (dp[i - 1][j][k] !== Number.MAX_VALUE) {
                    dp[i][A[i].charCodeAt(0) - 97][k] = Math.min(
                        dp[i][A[i].charCodeAt(0) - 97][k],
                        dp[i - 1][j][k] + A[i].length - ((A[i].charCodeAt(A[i].length - 1) - 97) === j ? 1 : 0)
                    );
                }
            }
        }
    }

    // lets find minimum size of N'th string for all possible i and j
    let ans = Number.MAX_VALUE;
    for (let i = 0; i < 26; i++) {
        for (let j = 0; j < 26; j++) {
            ans = Math.min(ans, dp[N - 1][i][j]);
        }
    }
    return ans;
}

// Input
const N = 3;
const A = ["aa", "ab", "bc"];

// Function Call
console.log(minimizeSizeOfString(A, N));  

Output
4

Time Complexity: O(N * 26 * 26)
Auxiliary Space: O(N * 26 * 26)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads