Minimize the size of the string formed by performing following operation
Last Updated :
21 Mar, 2024
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();
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));
Time Complexity: O(N * 26 * 26)
Auxiliary Space: O(N * 26 * 26)
Share your thoughts in the comments
Please Login to comment...