Smallest length string with repeated replacement of two distinct adjacent
Given a string of any combination of three letters ‘a’, ‘b’, and ‘c’, find length of the smallest string that can be obtained by applying the following operation repeatedly:
Take any two adjacent, distinct characters and replace them with the third.
Examples:
Input : cab
Output : 2
We can select any two adjacent letters,
say 'ca' and transform it into 'b', this
leaves us with string 'bb' of length two.
Input : bcab
Output : 1
Selecting 'bc' and transforming it to 'a'
leaves us with 'aab'. We can then select
'ab' and transform it to 'c', giving 'ac'.
This can further be transformed into 'b',
which is of length one.
A naive way to do this would be to find all possible replacements, and recurse until we find the minimum string. This would take exponential time.
Lemma: Order of letters does not effect the length or value of minimum string.
Proof By Induction
Base case: Take string ‘ab’ and ‘ba’, they both reduce to ‘c’
Inductive Hypothesis: All strings of length <= k reduce to the same string assuming the number of occurrences of each letter in each string is the same.
Inductive Step: Take two strings of length k + 1 having same number of occurrences of each letter. Find a pair of letters that are adjacent
in both strings. Here, two cases arise:
- We manage to find such a pair of letters. We can then replace these letters with the third letter, thus getting two strings of length k having same occurrences of each letter, which by inductive hypothesis reduces to the same string. i.e. We have ‘abcacb’ and ‘accbba’ and reduce ‘ac’ in both strings, we thus get ‘abcbb’ and ‘bcbba’.
- We cannot find such a pair. This arises when all letters in the string are the same. In this case, the two strings themselves are the same i.e. ‘ccccccc’ and ‘ccccccc’.
Thus by induction we have proven this lemma.
Dynamic Programming Approach: We can now devise a function using Dynamic Programming to solve this problem.
C++
#include<bits/stdc++.h>
using namespace std;
#define MAX_LEN 110
int DP[MAX_LEN][MAX_LEN][MAX_LEN];
int length( int a, int b, int c)
{
if (a < 0 or b < 0 or c < 0)
if (DP[a][b] != -1)
return DP[a][b];
if (a == 0 && b == 0)
return (DP[a][b] = c);
if (a == 0 && c == 0)
return (DP[a][b] = b);
if (b == 0 && c == 0)
return (DP[a][b] = a);
if (a == 0)
return (DP[a][b] =
length(a + 1, b - 1, c - 1));
if (b == 0)
return (DP[a][b] =
length(a - 1, b + 1, c - 1));
if (c == 0)
return (DP[a][b] =
length(a - 1, b - 1, c + 1));
return (DP[a][b] =
min(length(a - 1, b - 1, c + 1),
min(length(a - 1, b + 1, c - 1),
length(a + 1, b - 1, c - 1))));
}
int stringReduction(string str)
{
int n = str.length();
int count[3] = {0};
for ( int i=0; i<n; ++i)
count[str[i]- 'a' ]++;
for ( int i = 0; i <= count[0]; ++i)
for ( int j = 0; j < count[1]; ++j)
for ( int k = 0; k < count[2]; ++k)
DP[i][j][k] = -1;
return length(count[0], count[1], count[2]);
}
int main()
{
string str = "abcbbaacb" ;
cout << stringReduction(str);
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int MAX_LEN = 110 ;
static int [][][] DP = new int [MAX_LEN][MAX_LEN][MAX_LEN];
static int length( int a, int b, int c)
{
if (a < 0 || b < 0 || c < 0 )
if (DP[a][b] != - 1 )
return DP[a][b];
if (a == 0 && b == 0 )
return (DP[a][b] = c);
if (a == 0 && c == 0 )
return (DP[a][b] = b);
if (b == 0 && c == 0 )
return (DP[a][b] = a);
if (a == 0 )
return (DP[a][b] =
length(a + 1 , b - 1 , c - 1 ));
if (b == 0 )
return (DP[a][b] =
length(a - 1 , b + 1 , c - 1 ));
if (c == 0 )
return (DP[a][b] =
length(a - 1 , b - 1 , c + 1 ));
DP[a][b] =
Math.min(length(a - 1 , b - 1 , c + 1 ),
Math.min(length(a - 1 , b + 1 , c - 1 ),
length(a + 1 , b - 1 , c - 1 )));
return DP[a][b];
}
static int stringReduction(String str)
{
int n = str.length();
int [] count = new int [ 3 ];
for ( int i = 0 ; i < n; ++i)
count[str.charAt(i) - 'a' ]++;
for ( int i = 0 ; i <= count[ 0 ]; ++i)
for ( int j = 0 ; j < count[ 1 ]; ++j)
for ( int k = 0 ; k < count[ 2 ]; ++k)
DP[i][j][k] = - 1 ;
return length(count[ 0 ], count[ 1 ], count[ 2 ]);
}
public static void main (String[] args) {
String str = "abcbbaacb" ;
System.out.println(stringReduction(str));
}
}
|
Python3
def length(a, b, c):
global DP
if a < 0 or b < 0 or c < 0 :
return 0
if (DP[a][b] ! = - 1 ):
return DP[a][b]
if (a = = 0 and b = = 0 ):
DP[a][b] = c
return c
if (a = = 0 and c = = 0 ):
DP[a][b] = b
return b
if (b = = 0 and c = = 0 ):
DP[a][b] = a
return a
if (a = = 0 ):
DP[a][b] = length(a + 1 , b - 1 ,
c - 1 )
return DP[a][b]
if (b = = 0 ):
DP[a][b] = length(a - 1 , b + 1 ,
c - 1 )
return DP[a][b]
if (c = = 0 ):
DP[a][b] = length(a - 1 , b - 1 ,
c + 1 )
return DP[a][b]
x = length(a - 1 , b - 1 , c + 1 )
y = length(a - 1 , b + 1 , c - 1 )
z = length(a + 1 , b - 1 , c - 1 )
DP[a][b] = min ([x, y, z])
return DP[a][b]
def stringReduction( str ):
n = len ( str )
count = [ 0 ] * 3
for i in range (n):
count[ ord ( str [i]) - ord ( 'a' )] + = 1
return length(count[ 0 ], count[ 1 ], count[ 2 ])
if __name__ = = '__main__' :
DP = [[[ - 1 for i in range ( 110 )]
for i in range ( 110 )]
for i in range ( 110 )]
str = "abcbbaacb"
print (stringReduction( str ))
|
C#
using System;
public class GFG
{
static int MAX_LEN = 110;
static int [,,] DP = new int [MAX_LEN, MAX_LEN, MAX_LEN];
static int length( int a, int b, int c)
{
if (a < 0 || b < 0 || c < 0)
if (DP[a, b, c] != -1)
return DP[a, b, c];
if (a == 0 && b == 0)
return (DP[a, b, c] = c);
if (a == 0 && c == 0)
return (DP[a, b, c] = b);
if (b == 0 && c == 0)
return (DP[a, b, c] = a);
if (a == 0)
return (DP[a, b, c] =
length(a + 1, b - 1, c - 1));
if (b == 0)
return (DP[a, b, c] =
length(a - 1, b + 1, c - 1));
if (c == 0)
return (DP[a, b, c] =
length(a - 1, b - 1, c + 1));
DP[a, b, c] =
Math.Min(length(a - 1, b - 1, c + 1),
Math.Min(length(a - 1, b + 1, c - 1),
length(a + 1, b - 1, c - 1)));
return DP[a, b, c];
}
static int stringReduction( string str)
{
int n = str.Length;
int [] count = new int [3];
for ( int i = 0; i < n; ++i)
count[str[i] - 'a' ]++;
for ( int i = 0; i <= count[0]; ++i)
for ( int j = 0; j < count[1]; ++j)
for ( int k = 0; k < count[2]; ++k)
DP[i, j, k] = -1;
return length(count[0], count[1], count[2]);
}
static public void Main ()
{
string str = "abcbbaacb" ;
Console.WriteLine(stringReduction(str));
}
}
|
Javascript
<script>
let MAX_LEN = 110;
let DP = new Array(MAX_LEN);
for (let i = 0; i < DP.length; i++)
{
DP[i] = new Array(MAX_LEN);
for (let j = 0; j < DP[i].length; j++)
{
DP[i][j] = new Array(MAX_LEN);
for (let k = 0; k < MAX_LEN; k++)
{
DP[i][j][k] = 0;
}
}
}
function length(a, b, c)
{
if (a < 0 || b < 0 || c < 0)
if (DP[a][b] != -1)
return DP[a][b];
if (a == 0 && b == 0)
return (DP[a][b] = c);
if (a == 0 && c == 0)
return (DP[a][b] = b);
if (b == 0 && c == 0)
return (DP[a][b] = a);
if (a == 0)
return (DP[a][b] =
length(a + 1, b - 1, c - 1));
if (b == 0)
return (DP[a][b] =
length(a - 1, b + 1, c - 1));
if (c == 0)
return (DP[a][b] =
length(a - 1, b - 1, c + 1));
DP[a][b] =
Math.min(length(a - 1, b - 1, c + 1),
Math.min(length(a - 1, b + 1, c - 1),
length(a + 1, b - 1, c - 1)));
return DP[a][b];
}
function stringReduction(str)
{
let n = str.length;
let count = new Array(3);
for (let i = 0; i < 3; i++)
{
count[i] = 0;
}
for (let i = 0; i < n; ++i)
count[str[i].charCodeAt(0) - 'a' .charCodeAt(0)]++;
for (let i = 0; i <= count[0]; ++i)
for (let j = 0; j < count[1]; ++j)
for (let k = 0; k < count[2]; ++k)
DP[i][j][k] = -1;
return length(count[0], count[1], count[2]);
}
let str = "abcbbaacb" ;
document.write(stringReduction(str));
</script>
|
In the worst case, each letter is present in 1/3rd of the whole string. This leads to auxiliary space = O(N3) and time complexity = O(N3)
Space Complexity = O(N^3)
Time Complexity = O(N^3)
Mathematical Approach:
We can do better than this using three main principles:
- If the string cannot be reduced further, then all letters in the string are the same.
- The length of minimum string is either <= 2 or equal to the length of original string, or 2 < minimum string length < original string length is never true.
- If each letter of the string is present an odd amount of times, after one reduction step, they shall all be present an even amount of times. The converse is also true, that is, if each letter of the string is present an even amount of times, they shall be present an odd amount of times after one reduction step.
These can be proven as follows:
- If any two different letters are present, we can select these and reduce string length further.
- Proof by contradiction:
Assume we have a reduced string of length less than original string. For example ‘bbbbbbb’. Then this string must have originated from a string like ‘acbbbbbb’, ‘bbacbbbb’ or any other such combination of the same. In this case, we could have selected ‘bc’ instead of ‘ac’ and reduced further.
- From the recursive step above, we increase one letter by one and decrease the other two by one. So if we had a combination as (odd, odd, odd), then it would become (odd + 1, odd – 1, odd – 1) or (even, even, even). The reverse is shown in a similar fashion.
Now we can combine the above principles.
If the string consists of the same letter repeating, it’s minimum reduced string is itself, and length is the length of the string.
Now, the other possible options are reduced string being of one character length or two. Now if all characters are present an even number of times, or an odd number of times, the only answer that is possible is 2, because (0, 2, 0) is (even, even, even) while (0, 1, 0) is (even, odd, even) so only 2 preserves this evenness.
In any other condition, the answer becomes 1.
Implementation:
C++
#include<bits/stdc++.h>
using namespace std;
int stringReduction(string str)
{
int n = str.length();
int count[3] = {0};
for ( int i=0; i<n; ++i)
count[str[i]- 'a' ]++;
if (count[0] == n || count[1] == n ||
count[2] == n)
return n;
if ((count[0] % 2) == (count[1] % 2) &&
(count[1] % 2) == (count[2] % 2))
return 2;
return 1;
}
int main()
{
string str = "abcbbaacb" ;
cout << stringReduction(str);
return 0;
}
|
Java
public class GFG {
static int stringReduction(String str) {
int n = str.length();
int count[] = new int [ 3 ];
for ( int i = 0 ; i < n; ++i) {
count[str.charAt(i) - 'a' ]++;
}
if (count[ 0 ] == n || count[ 1 ] == n
|| count[ 2 ] == n) {
return n;
}
if ((count[ 0 ] % 2 ) == (count[ 1 ] % 2 )
&& (count[ 1 ] % 2 ) == (count[ 2 ] % 2 )) {
return 2 ;
}
return 1 ;
}
public static void main(String[] args) {
String str = "abcbbaacb" ;
System.out.println(stringReduction(str));
}
}
|
Python3
def stringReduction( str ):
n = len ( str )
count = [ 0 ] * 3
for i in range (n):
count[ ord ( str [i]) - ord ( 'a' )] + = 1
if (count[ 0 ] = = n or count[ 1 ] = = n or
count[ 2 ] = = n):
return n
if ((count[ 0 ] % 2 ) = = (count[ 1 ] % 2 ) and
(count[ 1 ] % 2 ) = = (count[ 2 ] % 2 )):
return 2
return 1
if __name__ = = "__main__" :
str = "abcbbaacb"
print (stringReduction( str ))
|
C#
using System;
public class GFG {
static int stringReduction(String str) {
int n = str.Length;
int []count = new int [3];
for ( int i = 0; i < n; ++i) {
count[str[i] - 'a' ]++;
}
if (count[0] == n || count[1] == n
|| count[2] == n) {
return n;
}
if ((count[0] % 2) == (count[1] % 2)
&& (count[1] % 2) == (count[2] % 2)) {
return 2;
}
return 1;
}
public static void Main() {
String str = "abcbbaacb" ;
Console.WriteLine(stringReduction(str));
}
}
|
Javascript
<script>
function stringReduction(str)
{
var n = str.length;
var count = Array.from({length: 3}, (_, i) => 0);
for ( var i = 0; i < n; ++i)
{
count[str.charAt(i).charCodeAt(0) -
'a' .charCodeAt(0)]++;
}
if (count[0] == n ||
count[1] == n ||
count[2] == n)
{
return n;
}
if ((count[0] % 2) == (count[1] % 2) &&
(count[1] % 2) == (count[2] % 2))
{
return 2;
}
return 1;
}
var str = "abcbbaacb" ;
document.write(stringReduction(str));
</script>
|
PHP
<?php
function stringReduction( $str )
{
$n = strlen ( $str );
$count = array_fill (0, 3, 0);
for ( $i = 0; $i < $n ; ++ $i )
$count [ord( $str [ $i ]) - ord( 'a' )]++;
if ( $count [0] == $n || $count [1] == $n ||
$count [2] == $n )
return $n ;
if (( $count [0] % 2) == ( $count [1] % 2) &&
( $count [1] % 2) == ( $count [2] % 2))
return 2;
return 1;
}
$str = "abcbbaacb" ;
print (stringReduction( $str ));
?>
|
Time Complexity: O(n)
Auxiliary Space: O(1)
Last Updated :
07 Jan, 2024
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...