Skip to content

Commit eeafc92

Browse files
Solution for Min Deletions for pal
1 parent 38338fa commit eeafc92

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ Happy to accept any contributions to this in any langugage.
168168
2. [Solution Recursion Brute Force](./dynamic_programming/CountOfPalindromicSubstrings.ts)
169169
3. [Solution Top Down DP](./dynamic_programming/CountOfPalindromicSubstrings.ts)
170170
4. [Solution Bottoms Up DP](./dynamic_programming/CountOfPalindromicSubstrings.ts)
171+
12. Minimum Deletions Required to make a Palindrome
172+
1. [Solution Brute Force](./dynamic_programming/MinStringDeletionPalindrome.ts)
173+
2. [Solution DP Bottoms Up](./dynamic_programming/MinStringDeletionPalindrome.ts)
174+
3. [Solution DP Top Down](./dynamic_programming/MinStringDeletionPalindrome.ts)
171175

172176
# TODO Items (More topics to explore further)
173177
* [All TODO Items](./TODO.md)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
class MinStringDeletionPalindrome {
2+
3+
/**
4+
* We recursively go over the input string in order to find out the deletion count. At each recursion level,
5+
* we keep a counter of the number of deletions made, starting with 0. With each recursion, there is one of
6+
* the 2 possibilities. If the ends match, we recurse for the substring. If the ends do not match, we either
7+
* skip the left or the right, either ways there is 1 deletion made. We calculate the min of any deletion.
8+
*
9+
* Time: O(2^n) since at each character position, we make 2 choices for recursion.
10+
* Space: O(n) since the max depth of recursion is n.
11+
*
12+
* @param input
13+
*/
14+
getMinDeletionBF(input: string) {
15+
16+
function find(beg: number, end: number, deletions: number = 0) {
17+
18+
// Base Conditions
19+
if (end <= beg) {
20+
return deletions;
21+
}
22+
23+
// Case 1: Ends are equal, so continue with the substring.
24+
if (input[beg] === input[end]) {
25+
return find(beg + 1, end - 1, deletions)
26+
}
27+
28+
// Case 2: Ends are not equal, check with left included or right included.
29+
return Math.min(find(beg + 1, end, deletions + 1), find(beg, end - 1, deletions + 1))
30+
}
31+
32+
return find(0, input.length - 1, 0)
33+
}
34+
35+
/**
36+
* Adds memoization to the recursive solution.
37+
*
38+
* Time: O(n^2) since we calculate result for each pair of beg and end at least once in the worst case.
39+
* Space: O(n^2) + O(n) for stage and recursion.
40+
*
41+
* @param input
42+
*/
43+
getMinDeletionDPTD(input: string) {
44+
45+
const dp: number[][] = Array.from({length: input.length}, () => Array(input.length));
46+
function find(beg: number, end: number, deletions: number = 0) {
47+
48+
// Base Conditions
49+
if (end <= beg) {
50+
return deletions;
51+
}
52+
53+
if (dp[beg][end] !== undefined) {
54+
return dp[beg][end];
55+
}
56+
57+
// Case 1: Ends are equal, so continue with the substring.
58+
if (input[beg] === input[end]) {
59+
dp[beg][end] = find(beg + 1, end - 1, deletions)
60+
return dp[beg][end];
61+
}
62+
63+
// Case 2: Ends are not equal, check with left included or right included.
64+
dp[beg][end] = Math.min(find(beg + 1, end, deletions + 1), find(beg, end - 1, deletions + 1))
65+
return dp[beg][end];
66+
}
67+
68+
return find(0, input.length - 1, 0)
69+
}
70+
71+
/**
72+
* Builds a DP table using all the valid pairs of beg and end. For all the pairs with the same beg and end, the
73+
* deletions are 0, for others we use the following forumale:
74+
* dp[beg][end] = 1 + Min(dp[beg][end - 1], dp[beg + 1][end])
75+
*
76+
* Time: O(n^2) and Space: O(n^2) for making all valid combinations of beg and end.
77+
*
78+
* @param input
79+
*/
80+
getMinDeletionDPBU(input: string) {
81+
82+
// DP Table
83+
const dp: number[][] = Array.from({length: input.length}, () => Array(input.length));
84+
85+
// Init for the diagnols
86+
for (let idx = 0; idx < input.length; idx++) dp[idx][idx] = 0;
87+
88+
// Creating for all valid pairs of start and end.
89+
for (let beg = input.length - 1; beg >= 0; beg--) {
90+
for (let end = beg + 1; end < input.length; end++) {
91+
if (input[beg] === input[end]) {
92+
// Case 1: Extremes match, total deletions would be min of the center substring.
93+
// Additional check of 0 is done for the edge cases, where there is nothing valid in subrange.
94+
dp[beg][end] = (dp[beg + 1][end - 1] || 0);
95+
} else {
96+
// Ends do not match, deletions are 1 + min of left or right.
97+
dp[beg][end] = 1 + Math.min(dp[beg + 1][end], dp[beg][end - 1])
98+
}
99+
}
100+
}
101+
102+
return dp[0][input.length - 1]
103+
}
104+
105+
}
106+
107+
function testMinStringDeletions(input: string) {
108+
const counter = new MinStringDeletionPalindrome();
109+
console.log(`BF: Min Items deletion for the input ${input} would be ${counter.getMinDeletionBF(input)}`);
110+
console.log(`DP TD: Min Items deletion for the input ${input} would be ${counter.getMinDeletionDPTD(input)}`);
111+
console.log(`DP BU: Min Items deletion for the input ${input} would be ${counter.getMinDeletionDPBU(input)}`);
112+
}
113+
114+
testMinStringDeletions("abdbca")
115+
testMinStringDeletions("cddpd")
116+
testMinStringDeletions("pqr")

0 commit comments

Comments
 (0)