Minimum steps to delete a string (original) (raw)

Given a string **s of size **n consisting of digits only, find the minimum number of steps required to delete the entire string. In one step, you can delete any substring of s that is a palindrome. After deletion, the remaining parts of the string are concatenated.

**Examples:

**Input: s = "2553432"
**Output: 2
**Explanation: In the first step, remove "55", after which the string becomes "23432", which is a palindrome and can be removed in the second step.

**Input: s = "1234"
**Output: 4
**Explanation: Each character is removed individually since no longer palindromic substring exist.

Table of Content

[Naive Approach] - Using Recursion - Exponential Time

The idea is to solve the problem recursively by trying all possible ways to delete the current substring and taking the minimum operations among them.

For every substring str[start...end]:

Consider the string: s= "2553432". We start from the first character and try all possible choices.

So, the minimum operations needed to delete the string are: 2

C++ `

#include <bits/stdc++.h> using namespace std;

int solve(string &str, int start, int end) {

// if string is empty
if (start > end)
    return 0;

// if string has one character
if (start == end)
    return 1;

// if string has two same characters
if (start + 1 == end && str[start] == str[end])
    return 1;

// delete first character separately
int res = 1 + solve(str, start + 1, end);

// if first two characters are same
if (str[start] == str[start + 1])
    res = min(res, 1 + solve(str, start + 2, end));

// match first character with same character later
for (int i = start + 2; i <= end; i++) {
    if (str[start] == str[i]) {
        res = min(res, solve(str, start + 1, i - 1) + solve(str, i + 1, end));
    }
}

return res;

}

int minStepToDeleteString(string &str) { return solve(str, 0, str.size() - 1); }

int main() {

string str = "2553432";

cout << minStepToDeleteString(str);

return 0;

}

Java

class GFG {

static int solve(String str, int start, int end) {

    // if string is empty
    if (start > end)
        return 0;

    // if string has one character
    if (start == end)
        return 1;

    // if string has two same characters
    if (start + 1 == end && str.charAt(start) == str.charAt(end))
        return 1;

    // delete first character separately
    int res = 1 + solve(str, start + 1, end);

    // if first two characters are same
    if (str.charAt(start) == str.charAt(start + 1))
        res = Math.min(res,
                       1 + solve(str, start + 2, end));

    // match first character with same character later
    for (int i = start + 2; i <= end; i++) {
        if (str.charAt(start) == str.charAt(i)) {
            res = Math.min(res, solve(str, start + 1, i - 1) + solve(str, i + 1, end));
        }
    }

    return res;
}

static int minStepToDeleteString(String str) {
    return solve(str, 0, str.length() - 1);
}

public static void main(String[] args) {

    String str = "2553432";

    System.out.println(minStepToDeleteString(str));
}

}

Python

def solve(str, start, end):

# if string is empty
if start > end:
    return 0

# if string has one character
if start == end:
    return 1

# if string has two same characters
if start + 1 == end and str[start] == str[end]:
    return 1

# delete first character separately
res = 1 + solve(str, start + 1, end)

# if first two characters are same
if str[start] == str[start + 1]:
    res = min(res,
              1 + solve(str, start + 2, end))

# match first character with same character later
for i in range(start + 2, end + 1):
    if str[start] == str[i]:
        res = min(res,
                  solve(str, start + 1, i - 1) +
                  solve(str, i + 1, end))

return res

def minStepToDeleteString(str): return solve(str, 0, len(str) - 1)

str = "2553432"

print(minStepToDeleteString(str))

C#

using System;

class GFG {

static int solve(string str, int start, int end) {

    // if string is empty
    if (start > end)
        return 0;

    // if string has one character
    if (start == end)
        return 1;

    // if string has two same characters
    if (start + 1 == end && str[start] == str[end])
        return 1;

    // delete first character separately
    int res = 1 + solve(str, start + 1, end);

    // if first two characters are same
    if (str[start] == str[start + 1])
        res = Math.Min(res,
                       1 + solve(str, start + 2, end));

    // match first character with same character later
    for (int i = start + 2; i <= end; i++) {
        if (str[start] == str[i]) {
            res = Math.Min(res, solve(str, start + 1, i - 1) + solve(str, i + 1, end));
        }
    }

    return res;
}

static int minStepToDeleteString(string str) {
    return solve(str, 0, str.Length - 1);
}

static void Main() {

    string str = "2553432";

    Console.WriteLine(minStepToDeleteString(str));
}

}

JavaScript

function solve(str, start, end) {

// if string is empty
if (start > end)
    return 0;

// if string has one character
if (start === end)
    return 1;

// if string has two same characters
if (start + 1 === end && str[start] === str[end])
    return 1;

// delete first character separately
let res = 1 + solve(str, start + 1, end);

// if first two characters are same
if (str[start] === str[start + 1])
    res = Math.min(res,
                   1 + solve(str, start + 2, end));

// match first character with same character later
for (let i = start + 2; i <= end; i++) {
    if (str[start] === str[i]) {
        res = Math.min(res,solve(str, start + 1, i - 1) + solve(str, i + 1, end));
    }
}

return res;

}

function minStepToDeleteString(str) { return solve(str, 0, str.length - 1); }

// Drive code let str = "2553432"; console.log(minStepToDeleteString(str));

`

[Expected Approach] - Using Memoization - O(n ^ 3) Time and O(n ^ 2) Space

In the recursive approach, the same substring is solved again and again, which makes the solution slow. To avoid this, we use memoization.

We create a 2D array memo[][] to store the minimum operations needed for every substring str[i...j]. Before solving any substring, we first check whether its answer is already stored in memo[][]. If it is already present, we directly return that value instead of calculating it again.

#include <bits/stdc++.h> using namespace std;

// Recursive function to find the minimum // operations required to delete a string int solve(string &str, int start, int end, vector<vector> &memo) {

// if the string is empty no operations required
if (start > end)
    return 0;

// if the string has only one character
// one operation required
if (start == end)
    return 1;

// if string has only two characters
// and both the characters are same
if (start + 1 == end && str[start] == str[end])
    return 1;

// if result is already calculated
if (memo[start][end] != -1)
    return memo[start][end];

// delete first character separately
int res = 1 + solve(str, start + 1, end, memo);

// if first two characters are same
if (str[start] == str[start + 1])
    res = min(res, 1 + solve(str, start + 2, end, memo));

// match first character with same character later
for (int i = start + 2; i <= end; i++) {

    if (str[start] == str[i]) {

        res = min(res,
                  solve(str, start + 1, i - 1, memo) +
                  solve(str, i + 1, end, memo));
    }
}

return memo[start][end] = res;

}

// Function to find the minimum operations // to delete the string entirely int minStepToDeleteString(string str) {

int n = str.size();

// to store results of subproblems
vector<vector<int>> memo(n, vector<int>(n, -1));

return solve(str, 0, n - 1, memo);

}

int main() {

string str = "2553432";

cout << minStepToDeleteString(str);

return 0;

}

Java

import java.util.Arrays;

class GFG {

// Recursive function to find the minimum
// operations required to delete a string
static int solve(String str, int start, int end,
                 int[][] memo) {

    // if the string is empty
    // no operations required
    if (start > end)
        return 0;

    // if the string has only one character
    // one operation required
    if (start == end)
        return 1;

    // if string has only two characters
    // and both the characters are same
    if (start + 1 == end &&str.charAt(start) == str.charAt(end))
        return 1;

    // if result is already calculated
    if (memo[start][end] != -1)
        return memo[start][end];

    // delete first character separately
    int res = 1 + solve(str, start + 1, end, memo);

    // if first two characters are same
    if (str.charAt(start) == str.charAt(start + 1))
        res = Math.min(res, 1 + solve(str, start + 2, end, memo));

    // match first character with same character later
    for (int i = start + 2; i <= end; i++) {

        if (str.charAt(start) == str.charAt(i)) {

            res = Math.min(res,
                           solve(str, start + 1, i - 1, memo) +
                           solve(str, i + 1, end, memo));
        }
    }

    return memo[start][end] = res;
}

// Function to find the minimum operations
// to delete the string entirely
static int minStepToDeleteString(String str) {

    int n = str.length();

    // to store results of subproblems
    int[][] memo = new int[n][n];

    for (int i = 0; i < n; i++) {
        Arrays.fill(memo[i], -1);
    }

    return solve(str, 0, n - 1, memo);
}

public static void main(String[] args) {

    String str = "2553432";

    System.out.println(minStepToDeleteString(str));
}

}

Python

Recursive function to find the minimum

operations required to delete a string

def solve(str, start, end, memo):

# if the string is empty
# no operations required
if start > end:
    return 0

# if the string has only one character
# one operation required
if start == end:
    return 1

# if string has only two characters
# and both the characters are same
if start + 1 == end and str[start] == str[end]:
    return 1

# if result is already calculated
if memo[start][end] != -1:
    return memo[start][end]

# delete first character separately
res = 1 + solve(str, start + 1, end, memo)

# if first two characters are same
if str[start] == str[start + 1]:
    res = min(res, 1 + solve(str, start + 2, end, memo))

# match first character with same character later
for i in range(start + 2, end + 1):

    if str[start] == str[i]:

        res = min(res,
                  solve(str, start + 1, i - 1, memo) +
                  solve(str, i + 1, end, memo))

memo[start][end] = res
return res

Function to find the minimum operations

to delete the string entirely

def minStepToDeleteString(str):

n = len(str)

# to store results of subproblems
memo = [[-1 for _ in range(n)] for _ in range(n)]

return solve(str, 0, n - 1, memo)

if name == "main":

str = "2553432"

print(minStepToDeleteString(str))

C#

using System;

class GFG {

// Recursive function to find the minimum
// operations required to delete a string
static int solve(string str, int start, int end, int[,] memo) {

    // if the string is empty
    // no operations required
    if (start > end)
        return 0;

    // if the string has only one character
    // one operation required
    if (start == end)
        return 1;

    // if string has only two characters
    // and both the characters are same
    if (start + 1 == end && str[start] == str[end])
        return 1;

    // if result is already calculated
    if (memo[start, end] != -1)
        return memo[start, end];

    // delete first character separately
    int res = 1 + solve(str, start + 1, end, memo);

    // if first two characters are same
    if (str[start] == str[start + 1])
        res = Math.Min(res, 1 + solve(str, start + 2, end, memo));

    // match first character with same character later
    for (int i = start + 2; i <= end; i++) {

        if (str[start] == str[i]) {

            res = Math.Min(res,
                           solve(str, start + 1, i - 1, memo) +
                           solve(str, i + 1, end, memo));
        }
    }

    memo[start, end] = res;
    return res;
}

// Function to find the minimum operations
// to delete the string entirely
static int minStepToDeleteString(string str) {

    int n = str.Length;

    // to store results of subproblems
    int[,] memo = new int[n, n];

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            memo[i, j] = -1;
        }
    }

    return solve(str, 0, n - 1, memo);
}

static void Main() {

    string str = "2553432";

    Console.WriteLine(minStepToDeleteString(str));
}

}

JavaScript

// Recursive function to find the minimum // operations required to delete a string function solve(str, start, end, memo) {

// if the string is empty
// no operations required
if (start > end)
    return 0;

// if the string has only one character
// one operation required
if (start === end)
    return 1;

// if string has only two characters
// and both the characters are same
if (start + 1 === end && str[start] === str[end])
    return 1;

// if result is already calculated
if (memo[start][end] !== -1)
    return memo[start][end];

// delete first character separately
let res = 1 + solve(str, start + 1, end, memo);

// if first two characters are same
if (str[start] === str[start + 1])
    res = Math.min(res, 1 + solve(str, start + 2, end, memo));

// match first character with same character later
for (let i = start + 2; i <= end; i++) {

    if (str[start] === str[i]) {

        res = Math.min(res,
                       solve(str, start + 1, i - 1, memo) +
                       solve(str, i + 1, end, memo));
    }
}

memo[start][end] = res;
return res;

}

// Function to find the minimum operations // to delete the string entirely function minStepToDeleteString(str) {

let n = str.length;

// to store results of subproblems
let memo = Array.from({ length: n }, () => Array(n).fill(-1));

return solve(str, 0, n - 1, memo);

}

// Drive code let str = "2553432"; console.log(minStepToDeleteString(str));

`

[Expected Approach - 2] - Using Tabulation - O(n ^ 3) Time and O(n ^ 2) Space

The idea is to solve the problem using dynamic programming by building a 2D table dp[][] where each entry dp[i][j] represents the minimum operations required to delete the substring s[i..j]. We calculate these values by considering the deletion of a single character, deleting two consecutive identical characters together, and combining the results from splitting at positions where the current character reoccurs.

Consider the string: s= "2553432". We create a DP tabledp[][] where dp[i][j] stores the minimum operations required to delete substring str[i...j].

Hence, the minimum operations required are: 2

C++ `

#include <bits/stdc++.h> using namespace std;

int minStepToDeleteString(string &str) {

int n = str.size();

// dp[i][j] stores minimum operations
// required to delete substring str[i...j]
vector<vector<int>> dp(n + 1,
                       vector<int>(n + 1, 0));

// traverse all substring lengths
for (int len = 1; len <= n; len++) {

    // generate all substrings of length len
    for (int i = 0, j = len - 1; j < n; i++, j++) {

        // single character needs one operation
        if (len == 1) {
            dp[i][j] = 1;
            continue;
        }

        // delete current character separately
        dp[i][j] = 1 + dp[i + 1][j];

        // if first two characters are same,
        // delete them together
        if (str[i] == str[i + 1]) {

            dp[i][j] = min(dp[i][j],
                           1 + dp[i + 2][j]);
        }

        // match current character with same
        // character later in the string
        for (int k = i + 2; k <= j; k++) {

            if (str[i] == str[k]) {

                dp[i][j] = min(dp[i][j],
                               dp[i + 1][k - 1] +
                               dp[k + 1][j]);
            }
        }
    }
}

return dp[0][n - 1];

}

int main() {

string str = "2553432";
cout << minStepToDeleteString(str);

return 0;

}

Java

import java.util.Arrays;

class GFG {

static public int minStepToDeleteString(String str) {

    int n = str.length();

    // dp[i][j] stores minimum operations
    // required to delete substring str[i...j]
    int[][] dp = new int[n + 1][n + 1];

    // traverse all substring lengths
    for (int len = 1; len <= n; len++) {

        // generate all substrings of length len
        for (int i = 0, j = len - 1; j < n; i++, j++) {

            // single character needs one operation
            if (len == 1) {
                dp[i][j] = 1;
                continue;
            }

            // delete current character separately
            dp[i][j] = 1 + dp[i + 1][j];

            // if first two characters are same,
            // delete them together
            if (str.charAt(i) == str.charAt(i + 1)) {

                dp[i][j] = Math.min(dp[i][j],
                                    1 + dp[i + 2][j]);
            }

            // match current character with same
            // character later in the string
            for (int k = i + 2; k <= j; k++) {

                if (str.charAt(i) == str.charAt(k)) {

                    dp[i][j] = Math.min(dp[i][j],
                                        dp[i + 1][k - 1] +
                                        dp[k + 1][j]);
                }
            }
        }
    }

    return dp[0][n - 1];
}

public static void main(String[] args) {

    String str = "2553432";
    System.out.println(minStepToDeleteString(str));
}

}

Python

def minStepToDeleteString(str):

n = len(str)

# dp[i][j] stores minimum operations
# required to delete substring str[i...j]
dp = [[0 for _ in range(n + 1)]
         for _ in range(n + 1)]

# traverse all substring lengths
for length in range(1, n + 1):

    # generate all substrings of length length
    i = 0
    j = length - 1

    while j < n:

        # single character needs one operation
        if length == 1:
            dp[i][j] = 1

        else:

            # delete current character separately
            dp[i][j] = 1 + dp[i + 1][j]

            # if first two characters are same,
            # delete them together
            if str[i] == str[i + 1]:

                dp[i][j] = min(dp[i][j],
                               1 + dp[i + 2][j])

            # match current character with same
            # character later in the string
            for k in range(i + 2, j + 1):

                if str[i] == str[k]:

                    dp[i][j] = min(dp[i][j],
                                   dp[i + 1][k - 1] +
                                   dp[k + 1][j])

        i += 1
        j += 1

return dp[0][n - 1]

if name == "main":

str = "2553432"

print(minStepToDeleteString(str))

C#

using System;

public class GFG {

public static int minStepToDeleteString(string str) {

    int n = str.Length;

    // dp[i][j] stores minimum operations
    // required to delete substring str[i...j]
    int[,] dp = new int[n + 1, n + 1];

    // traverse all substring lengths
    for (int len = 1; len <= n; len++) {

        // generate all substrings of length len
        for (int i = 0, j = len - 1; j < n; i++, j++) {

            // single character needs one operation
            if (len == 1) {
                dp[i, j] = 1;
                continue;
            }

            // delete current character separately
            dp[i, j] = 1 + dp[i + 1, j];

            // if first two characters are same,
            // delete them together
            if (str[i] == str[i + 1]) {

                dp[i, j] = Math.Min(dp[i, j],
                                    1 + dp[i + 2, j]);
            }

            // match current character with same
            // character later in the string
            for (int k = i + 2; k <= j; k++) {

                if (str[i] == str[k]) {

                    dp[i, j] = Math.Min(dp[i, j],
                                        dp[i + 1, k - 1] +
                                        dp[k + 1, j]);
                }
            }
        }
    }

    return dp[0, n - 1];
}

public static void Main() {

    string str = "2553432";

    Console.WriteLine(minStepToDeleteString(str));
}

}

JavaScript

function minStepToDeleteString(str) {

let n = str.length;

// dp[i][j] stores minimum operations
// required to delete substring str[i...j]
let dp = Array.from({ length: n + 1 },
         () => Array(n + 1).fill(0));

// traverse all substring lengths
for (let len = 1; len <= n; len++) {

    // generate all substrings of length len
    for (let i = 0, j = len - 1; j < n; i++, j++) {

        // single character needs one operation
        if (len === 1) {
            dp[i][j] = 1;
            continue;
        }

        // delete current character separately
        dp[i][j] = 1 + dp[i + 1][j];

        // if first two characters are same,
        // delete them together
        if (str[i] === str[i + 1]) {

            dp[i][j] = Math.min(dp[i][j],
                                1 + dp[i + 2][j]);
        }

        // match current character with same
        // character later in the string
        for (let k = i + 2; k <= j; k++) {

            if (str[i] === str[k]) {

                dp[i][j] = Math.min(dp[i][j],
                                    dp[i + 1][k - 1] +
                                    dp[k + 1][j]);
            }
        }
    }
}

return dp[0][n - 1];

}

// Drive code let str = "2553432"; console.log(minStepToDeleteString(str));

`