Problem#
Given a string s
. In one step you can insert any character at any index of the string.
Return the minimum number of steps to make s
palindrome.
A Palindrome String is one that reads the same backward as well as forward.
Examples#
Example 1:
1
2
3
4
5
Input:
s = "zzazz"
Output:
0
Explanation: The string "zzazz" is already palindrome we don't need any insertions.
Example 2:
1
2
3
4
5
Input:
s = "mbadm"
Output:
2
Explanation: String can be "mbdadbm" or "mdbabdm".
Example 3:
1
2
3
4
5
Input:
s = "leetcode"
Output:
5
Explanation: Inserting 5 characters the string becomes "leetcodocteel".
Solution#
Method 1 - Recursion#
The minimum number of insertions in the string str[i...j]
can be given as:
minInsertions(str[i + 1...j - 1])
if str[i]
is equal to str[j]
min(minInsertions(str[i...j - 1]), minInsertions(str[i + 1...j])) + 1
otherwise
Code#
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int minInsertions (String s) {
return helper(s, 0, s.length () - 1, memo);
}
private int helper (String s, int i, int j) {
if (i >= j) {
return 0;
}
return s.charAt (i) == s.charAt (j) ? helper(s, i + 1, j - 1) : 1 + Math.min (helper(s, i + 1, j), helper(s, i, j - 1));
}
}
Method 2 - Top Down DP#
If we observe the above approach carefully, we can find that it exhibits
overlapping subproblems.
Suppose we want to find the minimum number of insertions in string “abcde”:
graph TD;
T(fabcdef) --- A(abcde)
A --- B(bcde) & C(abcd)
B --- D(cde) & E(bcd)
C --- F(bcd) & G(abc)
D --- H(de) & I(cd)
E --- J(cd) & K(bc)
F --- L(...)
G --- M(...)
H --- N(...)
I --- O(...)
J --- P(...)
K --- Q(...)
style E fill:#00758f
style F fill:#00758f
style I fill:#010aaa
style J fill:#010aaa
Code#
C++
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public :
vector< vector< int >> memo;
int dp (string & s,int i,int j)
{
if (i>= j) //Base case.
return 0 ;
if (memo[i][j]!=- 1 ) //Check if we have already calculated the value for the pair `i` and `j`.
return memo[i][j];
return memo[i][j]= s[i]== s[j]? dp(s,i+ 1 ,j- 1 ): 1 + min(dp(s,i+ 1 ,j),dp(s,i,j- 1 )); //Recursion as mentioned above.
}
int minInsertions (string s)
{
memo.resize(s.length(),vector< int > (s.length(),- 1 ));
return dp(s,0 ,s.length()- 1 );
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public int minInsertions (String s) {
int n = s.length ();
Integer[][] memo = new Integer[ n][ n] ;
return helper(s, 0, n - 1, memo);
}
private int helper (String s, int i, int j, Integer[][] memo) {
if (i >= j) { //Base case.
return 0;
}
if (memo[ i][ j] != null ) {
return memo[ i][ j] ;
}
return memo[ i][ j] = s.charAt (i) == s.charAt (j) ? helper(s, i + 1, j - 1, memo) : 1 + Math.min (helper(s, i + 1, j, memo), helper(s, i, j - 1, memo));
}
}
Method 3 - Bottom-up DP#
Code#
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public int minInsertions (String s) {
int n = s.length ();
int [][] dp = new int [ n][ n] ;
// Length of substring (2 to n)
for (int len = 2; len <= n; len++ ) {
// i = Starting index of substring
for (int i = 0; i + len - 1 < n; i++ ) {
// j - Ending index of substring
int j = i + len - 1;
// If characters match, use previous result
if (s.charAt (i) == s.charAt (j)) {
dp[ i][ j] = dp[ i + 1][ j - 1] ;
} else {
// Minimum insertions from either side
dp[ i][ j] = 1 + Math.min (dp[ i + 1][ j] , dp[ i][ j - 1] );
}
}
}
return dp[ 0][ n - 1] ;
}
}