Count of ways to empty given String by recursively removing all adjacent duplicates
Last Updated :
24 Mar, 2023
Given a string S, in one move it is allowed to remove two adjacent equal characters. After the removal, both endpoints of the removed characters are joined. Calculate the total number of ways to empty the string.
Example:
Input: S = aabccb
Output: 3
Explanation:
1. aabccb -> aabb -> aa
2. aabccb -> aabb -> bb
3. aabccb -> bccb -> bb
Hence, there are a total of 3 ways to empty the string after a valid set of moves.
Input: S = aabbc
Output: 0
Explanation: The string is of odd length, so it is not possible to empty the whole string.
Approach: The above problem can be solved with the help of Dynamic Programming. Follow the steps below to solve the problem:
- Let’s define a 2-d dp table dp[i][j] which will store the answer for the range [i, j].
- Define a recursive approach to solve the problem.
- To calculate dp[i][j], loop through all indices k between i and j where S[i] = S[k].
- Now for an individual k, the answer would be dp[i+1][k-1]*dp[k+1][j]*(Total number of ways to arrange the removals of the range).
- To calculate the last term of the equation, notice that the removal of the whole range [i+1, k-1] will take place before the removal of S[i] and S[k].
- So the total removals in the range will be (j – i + 1)/2 (since two elements are removed at a single time). From these removals have to choose (j – k)/2 removals.
- So the final formula will be
- Use memoization to not recalculate the states again.
- Check for the bases cases in the recursive function.
- The final answer will be dp[0][N-1]
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[505][505], choose[502][502];
int calc( int l, int r, string& s)
{
if ( abs (r - l) % 2 == 0) {
return 0;
}
if (l > r) {
return dp[l][r] = 1;
}
if (dp[l][r] != -1) {
return dp[l][r];
}
if ((r - l) == 1) {
if (s[l] == s[r]) {
dp[l][r] = 1;
}
else {
dp[l][r] = 0;
}
return dp[l][r];
}
int ans = 0;
for ( int k = l + 1; k <= r; k += 2) {
int temp = 1;
if (s[l] == s[k]) {
temp = calc(l + 1, k - 1, s)
* calc(k + 1, r, s)
* choose[(r - l + 1) / 2]
[(r - k) / 2];
ans += temp;
}
}
return dp[l][r] = ans;
}
int waysToClearString(string S)
{
memset (dp, -1, sizeof (dp));
int n = S.length();
choose[0][0] = 1;
for ( int i = 1; i <= n / 2; ++i) {
choose[i][0] = 1;
for ( int j = 1; j <= i; ++j) {
choose[i][j]
= (choose[i - 1][j]
+ choose[i - 1][j - 1]);
}
}
return calc(0, n - 1, S);
}
int main()
{
string S = "aabccb" ;
cout << waysToClearString(S);
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int [][]dp = new int [ 505 ][ 505 ];
static int [][]choose = new int [ 502 ][ 502 ];
static int calc( int l, int r, String s)
{
if (Math.abs(r - l) % 2 == 0 ) {
return 0 ;
}
if (l > r) {
return dp[l][r] = 1 ;
}
if (dp[l][r] != - 1 ) {
return dp[l][r];
}
if ((r - l) == 1 ) {
if (s.charAt(l) == s.charAt(r)) {
dp[l][r] = 1 ;
}
else {
dp[l][r] = 0 ;
}
return dp[l][r];
}
int ans = 0 ;
for ( int k = l + 1 ; k <= r; k += 2 ) {
int temp = 1 ;
if (s.charAt(l) == s.charAt(k)) {
temp = calc(l + 1 , k - 1 , s)
* calc(k + 1 , r, s)
* choose[((r - l + 1 ) / 2 )]
[((r - k) / 2 )];
ans += temp;
}
}
return dp[l][r] = ans;
}
static int waysToClearString(String S)
{
for ( int i= 0 ;i< 505 ;i++){
for ( int j= 0 ;j< 505 ;j++)
dp[i][j] = - 1 ;
}
int n = S.length();
choose[ 0 ][ 0 ] = 1 ;
for ( int i = 1 ; i <= (n / 2 ); ++i) {
choose[i][ 0 ] = 1 ;
for ( int j = 1 ; j <= i; ++j) {
choose[i][j]
= (choose[i - 1 ][j]
+ choose[i - 1 ][j - 1 ]);
}
}
return calc( 0 , n - 1 , S);
}
public static void main (String[] args)
{
String S = "aabccb" ;
System.out.println(waysToClearString(S));
}
}
|
Python3
import numpy as np
dp = np.zeros(( 505 , 505 ));
choose = np.zeros(( 502 , 502 ));
def calc(l, r, s) :
if ( abs (r - l) % 2 = = 0 ) :
return 0 ;
if (l > r) :
dp[l][r] = 1 ;
return dp[l][r]
if (dp[l][r] ! = - 1 ) :
return dp[l][r];
if ((r - l) = = 1 ) :
if (s[l] = = s[r]) :
dp[l][r] = 1 ;
else :
dp[l][r] = 0 ;
return dp[l][r];
ans = 0 ;
for k in range (l + 1 , r + 1 , 2 ) :
temp = 1 ;
if (s[l] = = s[k]) :
temp = calc(l + 1 , k - 1 , s) * calc(k + 1 , r, s) * choose[(r - l + 1 ) / / 2 ][(r - k) / / 2 ];
ans + = temp;
dp[l][r] = ans;
return dp[l][r]
def waysToClearString(S) :
for i in range ( 505 ):
for j in range ( 505 ) :
dp[i][j] = - 1
n = len (S);
choose[ 0 ][ 0 ] = 1 ;
for i in range ( 1 , (n / / 2 ) + 1 ) :
choose[i][ 0 ] = 1 ;
for j in range ( 1 , i + 1 ) :
choose[i][j] = choose[i - 1 ][j] + choose[i - 1 ][j - 1 ];
return calc( 0 , n - 1 , S);
if __name__ = = "__main__" :
S = "aabccb" ;
print (waysToClearString(S));
|
C#
using System;
using System.Collections.Generic;
class GFG{
static int [,]dp = new int [505,505];
static int [,]choose = new int [502,502];
static int calc( int l, int r, string s)
{
if (Math.Abs(r - l) % 2 == 0) {
return 0;
}
if (l > r) {
return dp[l,r] = 1;
}
if (dp[l,r] != -1) {
return dp[l,r];
}
if ((r - l) == 1) {
if (s[l] == s[r]) {
dp[l,r] = 1;
}
else {
dp[l,r] = 0;
}
return dp[l,r];
}
int ans = 0;
for ( int k = l + 1; k <= r; k += 2) {
int temp = 1;
if (s[l] == s[k]) {
temp = calc(l + 1, k - 1, s)
* calc(k + 1, r, s)
* choose[(r - l + 1) / 2,(r - k) / 2];
ans += temp;
}
}
return dp[l,r] = ans;
}
static int waysToClearString( string S)
{
for ( int i=0;i<505;i++){
for ( int j=0;j<505;j++)
dp[i,j] = -1;
}
int n = S.Length;
choose[0,0] = 1;
for ( int i = 1; i <= n / 2; ++i) {
choose[i,0] = 1;
for ( int j = 1; j <= i; ++j) {
choose[i,j]
= (choose[i - 1,j]
+ choose[i - 1,j - 1]);
}
}
return calc(0, n - 1, S);
}
public static void Main()
{
string S = "aabccb" ;
Console.Write(waysToClearString(S));
}
}
|
Javascript
<script>
var dp = new Array(505);
for ( var i = 0; i < dp.length; i++) {
dp[i] = new Array(505).fill(-1);
}
var choose = new Array(505);
for ( var i = 0; i < choose.length; i++) {
choose[i] = new Array(505).fill(0);
}
function calc(l, r, s) {
if (Math.abs(r - l) % 2 == 0) {
return 0;
}
if (l > r) {
return dp[l][r] = 1;
}
if (dp[l][r] != -1) {
return dp[l][r];
}
if ((r - l) == 1) {
if (s[l] == s[r]) {
dp[l][r] = 1;
}
else {
dp[l][r] = 0;
}
return dp[l][r];
}
let ans = 0;
for (let k = l + 1; k <= r; k += 2) {
let temp = 1;
if (s[l] == s[k]) {
temp = calc(l + 1, k - 1, s)
* calc(k + 1, r, s)
* choose[(Math.floor((r - l + 1) / 2))]
[(Math.floor((r - k) / 2))];
ans += temp;
}
}
return dp[l][r] = ans;
}
function waysToClearString(S) {
let n = S.length;
choose[0][0] = 1;
for (let i = 1; i <= Math.floor(n / 2); ++i) {
choose[i][0] = 1;
for (let j = 1; j <= i; ++j) {
choose[i][j]
= (choose[i - 1][j]
+ choose[i - 1][j - 1]);
}
}
return calc(0, n - 1, S);
}
let S = "aabccb" ;
document.write(waysToClearString(S));
</script>
|
Time Complexity: O(N^3)
Auxiliary Space: O(N^2)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...