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
- [Expected Approach] - Using Memoization - O(n ^ 3) Time and O(n ^ 2) Space
- [Expected Approach - 2] - Using Tabulation - O(n ^ 3) Time and O(n ^ 2) Space
[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]:
- First, delete the first character separately and recursively solve the remaining substring.
- If the first two characters are same, delete them together since they form a palindrome of length 2.
- Search for another occurrence of the first character later in the string. If found, both matching characters can be deleted as part of the same palindrome, so recursively solve the middle and remaining right parts.
- By exploring all possible deletions and choosing the minimum answer, we get the minimum operations required to delete the entire string.
Consider the string: s= "2553432". We start from the first character and try all possible choices.
- First, we can delete '2' separately and recursively solve "553432".
- Next, we check whether the first two characters are same, but '2' and '5' are different, so this option is skipped.
- Then, we search for another '2' later in the string and find it at the last index. **2 5 5 3 4 3 **2
- Now the problem is divided into: middle substring "55343" and remaining right substring""
- For "55343", the first two characters "55"are same, so we delete them together in one operation. The remaining string becomes "343", which is a palindrome and can be deleted in one more operation.
- Thus, the total operations required are: "55" -> 1 operation and "343" -> 1 operation
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 resdef 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.
- Create a 2D array memo[][] of size n x n initialized with -1.
- Define a recursive function for substring str[i...j].
- If the substring is empty, return 0.
- If the substring has one character, return 1.
- Delete the first character separately and solve the remaining substring.
- If the first two characters are same, delete them together.
- Search for another occurrence of the first character later in the string and solve the middle and remaining right parts.
- Store the minimum answer in memo[i][j].
- Return memo[0][n-1] as the final answer. C++ `
#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 resFunction 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.
- Create a 2D array dp[][] of size n x n.
- Traverse all substring lengths from 1 to n.
- If substring length is 1, set dp[i][j] = 1.
- Otherwise, first delete the current character separately.
- If the first two characters are same, delete them together.
- Search for another occurrence of the current character later in the string and update the minimum answer.
- Finally, return dp[0][n-1] as the minimum operations required to delete the entire string.
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].
- **Length = 1: Every single character needs one operation. dp[i][i] = 1
- **Length = 2: For substring "55": Both characters are same, so: dp[1][2] = 1 because "55" can be deleted together.
- **Length = 3: For substring "343": First and last characters are same, so "343" can be deleted in one operation. dp[3][5] = 1.
- **Length = 5: For substring "55343": Delete "55" together and then Remaining substring "343" already takes one operation. So: dp[1][5] = 2.
- **Full String: For substring "2553432": First and last characters are same. so middle substring "55343" already requires 2 operations, so the whole string can also be deleted in: 2 operations.
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));
`