Open In App

Count of ways to empty given String by recursively removing all adjacent duplicates

Last Updated : 24 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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 
     

dp[i+1][k-1]*dp[k+1][j]*{}^{(j-i + 1)/2}C_{(j - k)/2}

  • 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++

// C++ implementation for the above approach
#include <bits/stdc++.h>
using namespace std;
  
// Define the dp table globally
int dp[505][505], choose[502][502];
  
// Recursive function to calculate the dp
// values for range [L, R]
int calc(int l, int r, string& s)
{
  
    // The range is odd length
    if (abs(r - l) % 2 == 0) {
        return 0;
    }
  
    if (l > r) {
        return dp[l][r] = 1;
    }
  
    // The state is already calculated
    if (dp[l][r] != -1) {
        return dp[l][r];
    }
  
    // If the length is 2
    if ((r - l) == 1) {
        if (s[l] == s[r]) {
            dp[l][r] = 1;
        }
        else {
            dp[l][r] = 0;
        }
        return dp[l][r];
    }
  
    // Total answer for this state
    int ans = 0;
    for (int k = l + 1; k <= r; k += 2) {
  
        // Variable to store the current answer.
        int temp = 1;
  
        // Remove characters s[l] and s[i].
        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)
{
  
    // Initialize all the states of dp to -1
    memset(dp, -1, sizeof(dp));
  
    // Calculate all Combinations
    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);
}
  
// Driver Code
int main()
{
    string S = "aabccb";
  
    cout << waysToClearString(S);
  
    return 0;
}

                    

Java

// Java program for the above approach
import java.io.*;
class GFG
{
  
// Define the dp table globally
static int [][]dp = new int[505][505];
static int [][]choose = new int[502][502];
  
// Recursive function to calculate the dp
// values for range [L, R]
static int calc(int l, int r, String s)
{
  
    // The range is odd length
            if (Math.abs(r - l) % 2 == 0) {
                return 0;
            }
  
            if (l > r) {
                return dp[l][r] = 1;
            }
  
            // The state is already calculated
            if (dp[l][r] != -1) {
                return dp[l][r];
            }
  
            // If the length is 2
            if ((r - l) == 1) {
                if (s.charAt(l) == s.charAt(r)) {
                    dp[l][r] = 1;
                }
                else {
                    dp[l][r] = 0;
                }
                return dp[l][r];
            }
  
            // Total answer for this state
            int ans = 0;
            for (int k = l + 1; k <= r; k += 2) {
  
                // Variable to store the current answer.
                int temp = 1;
  
                // Remove characters s[l] and s[i].
                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)
{
  
    // Initialize all the states of dp to -1
    // Initialize all the states of dp to -1
    for(int i=0;i<505;i++){
        for(int j=0;j<505;j++)
            dp[i][j] = -1;
    }
  
            // Calculate all Combinations
            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);
}
  
// Driver Code
public static void main (String[] args)
{
    String S = "aabccb";
  
    System.out.println(waysToClearString(S));
}
}
  
// This code is contributed by sanjoy_62.

                    

Python3

# Python3 implementation for the above approach
import numpy as np
  
# Define the dp table globally
dp = np.zeros((505,505));
choose = np.zeros((502,502));
  
# Recursive function to calculate the dp
# values for range [L, R]
def calc(l, r, s) :
  
    # The range is odd length
    if (abs(r - l) % 2 == 0) :
        return 0;
  
    if (l > r) :
        dp[l][r] = 1;
        return dp[l][r]
  
    # The state is already calculated
    if (dp[l][r] != -1) :
        return dp[l][r];
  
    # If the length is 2
    if ((r - l) == 1) :
        if (s[l] == s[r]) :
            dp[l][r] = 1;
          
        else :
            dp[l][r] = 0;
          
        return dp[l][r];
      
    # Total answer for this state
    ans = 0;
      
    for k in range(l + 1, r + 1, 2) :
  
        # Variable to store the current answer.
        temp = 1;
  
        # Remove characters s[l] and s[i].
        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) :
  
  
    # Initialize all the states of dp to -1
    #memset(dp, -1, sizeof(dp));
      
    for i in range(505):
        for j in range(505) :
            dp[i][j] = -1
  
    # Calculate all Combinations
    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);
  
# Driver Code
if __name__ == "__main__" :
  
    S = "aabccb";
  
    print(waysToClearString(S));
  
    # This code is contributed by AnkThon

                    

C#

// C# implementation for the above approach
using System;
using System.Collections.Generic;
  
class GFG{
// Define the dp table globally
static int [,]dp = new int[505,505];
static int [,]choose = new int[502,502];
  
// Recursive function to calculate the dp
// values for range [L, R]
static int calc(int l, int r, string s)
{
  
    // The range is odd length
    if (Math.Abs(r - l) % 2 == 0) {
        return 0;
    }
  
    if (l > r) {
        return dp[l,r] = 1;
    }
  
    // The state is already calculated
    if (dp[l,r] != -1) {
        return dp[l,r];
    }
  
    // If the length is 2
    if ((r - l) == 1) {
        if (s[l] == s[r]) {
            dp[l,r] = 1;
        }
        else {
            dp[l,r] = 0;
        }
        return dp[l,r];
    }
  
    // Total answer for this state
    int ans = 0;
    for (int k = l + 1; k <= r; k += 2) {
  
        // Variable to store the current answer.
        int temp = 1;
  
        // Remove characters s[l] and s[i].
        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)
{
  
    // Initialize all the states of dp to -1
    for(int i=0;i<505;i++){
        for(int j=0;j<505;j++)
            dp[i,j] = -1;
    }
  
    // Calculate all Combinations
    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);
}
  
// Driver Code
public static void Main()
{
    string S = "aabccb";
  
    Console.Write(waysToClearString(S));
}
}
  
// This code is contributed by ipg2016107.

                    

Javascript

<script>
        // JavaScript Program to implement
        // the above approach
  
        // Define the dp table globally
        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);
        }
  
  
        // Recursive function to calculate the dp
        // values for range [L, R]
        function calc(l, r, s) {
  
            // The range is odd length
            if (Math.abs(r - l) % 2 == 0) {
                return 0;
            }
  
            if (l > r) {
                return dp[l][r] = 1;
            }
  
            // The state is already calculated
            if (dp[l][r] != -1) {
                return dp[l][r];
            }
  
            // If the length is 2
            if ((r - l) == 1) {
                if (s[l] == s[r]) {
                    dp[l][r] = 1;
                }
                else {
                    dp[l][r] = 0;
                }
                return dp[l][r];
            }
  
            // Total answer for this state
            let ans = 0;
            for (let k = l + 1; k <= r; k += 2) {
  
                // Variable to store the current answer.
                let temp = 1;
  
                // Remove characters s[l] and s[i].
                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) {
  
            // Initialize all the states of dp to -1
  
  
            // Calculate all Combinations
            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);
        }
  
        // Driver Code
  
        let S = "aabccb";
  
        document.write(waysToClearString(S));
  
// This code is contributed by Potta Lokesh
  
    </script>

                    

Output
3

Time Complexity: O(N^3)
Auxiliary Space: O(N^2)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads