Skip to content

Commit 38338fa

Browse files
Added other dynamic programming solutions for count palindromes
1 parent 8152263 commit 38338fa

File tree

1 file changed

+62
-20
lines changed

1 file changed

+62
-20
lines changed

dynamic_programming/CountOfPalindromicSubstrings.ts

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,36 +64,77 @@ class PalindromicSubstringsCounter {
6464
return result.size;
6565
}
6666

67+
countDPTopDown(input: string) {
68+
69+
const result: Set<string> = new Set();
70+
71+
function countHelper(input: string, beg: number, end: number, dp: boolean[][]) {
72+
73+
// Base Conditions where the palindrome is valid
74+
if (end < beg) return true;
75+
if (end == beg) {
76+
result.add(`${beg}|${end}`);
77+
dp[beg][end] = true;
78+
return true;
79+
}
80+
81+
if (dp[beg][end] !== undefined) {
82+
return dp[beg][end];
83+
}
84+
85+
countHelper(input, beg, end - 1, dp)
86+
countHelper(input, beg + 1, end, dp)
87+
88+
// Case: checking if the strings are palindrome using extremes matching and recursive substring.
89+
if (input[beg] === input[end] && countHelper(input, beg + 1, end - 1, dp)) {
90+
result.add(`${beg}|${end}`);
91+
dp[beg][end] = true;
92+
return true;
93+
} else {
94+
return false;
95+
}
96+
}
97+
98+
countHelper(input, 0, input.length - 1, Array.from({length: input.length}, () => Array(input.length)));
99+
// console.log(result)
100+
101+
return result.size;
102+
}
103+
104+
/**
105+
* Similar as the recursive brute force solution, but we also use memoization to save the pre-computed results.
106+
*
107+
* Time: O(n^2) since the results are computed at least once for each possible pair of beg and end.
108+
* Space: O(n^2) + O(n) for storing the memoized results and also the recursion depth.
109+
*
110+
* @param input
111+
*/
67112
countDPBottomsUp(input: string) {
68113

69114
// Create a DP table defining the number of valid palindromic strings for the substrings starting at (row) and ending at (col).
70-
const dp: number[][] = Array.from({length: input.length + 1}, () => Array(input.length).fill(0));
115+
const dp: boolean[][] = Array.from({length: input.length}, () => Array(input.length).fill(false));
71116

72117
// Init boundary conditions (for each substring starting and ending at the idx position, there is only 1 valid palindrome.)
73-
for (let idx = 0; idx < input.length; idx++) dp[idx][idx] = 1;
74-
75-
/** a b c d
76-
* a [1 2 3 4
77-
* b 5 6 2]
78-
* c 4 1
79-
*/
118+
for (let idx = 0; idx < input.length; idx++) dp[idx][idx] = true;
80119

120+
let total = input.length;
121+
81122
// Build the solution for all character range. DP row represents the starting char and col represents the ending char.
82-
for (let beg = input.length; beg >= 0; beg--) {
123+
for (let beg = input.length - 1; beg >= 0; beg--) {
83124
for (let end = beg + 1; end < input.length; end++) {
84-
85-
// Case 1: If the extremes are matching
86-
// If the substring at beg + 1:end - 1 are matching, we update 1 to the counter.
87-
// If the susbtrings are not matching, we dont have a palindrome, take the last one.
88-
if (input[beg] === input[end]) {
89-
dp[beg][end] = dp[beg + 1][end - 1];
125+
if (input[beg] === input[end] && beg + 1 === end) {
126+
// If the 2 extremes are equal and there is nothing in between
127+
dp[beg][end] = true
128+
total++
129+
} else if (input[beg] === input[end] && dp[beg + 1][end - 1]) {
130+
// If the extremes are matching, we need to ensure the left over substrings are also creating a palindrome
131+
dp[beg][end] = true
132+
total++
90133
}
91-
92-
dp[beg][end] += dp[beg + 1][end];
93134
}
94135
}
95136

96-
return dp[0][input.length - 1];
137+
return total;
97138
}
98139

99140
/**
@@ -103,7 +144,7 @@ class PalindromicSubstringsCounter {
103144
* @param end
104145
*/
105146
isValidPalindrome(input: string, beg: number, end: number) {
106-
while(end >= beg) {
147+
while(end >= beg) {
107148
if (input[end--] !== input[beg++]) return false;
108149
}
109150

@@ -115,7 +156,8 @@ function testCountPalindromeSubstring(input: string) {
115156
const counter = new PalindromicSubstringsCounter();
116157
console.log(`Counter BF for input: ${input} returned: ${counter.countBF(input)}`);
117158
console.log(`Counter BF Recursive for input: ${input} returned: ${counter.countBFRecursive(input)}`)
118-
// console.log(`Counter DP bottoms up for input: ${input} returned for ${counter.countDPBottomsUp(input)}`);
159+
console.log(`Counter DP Top down for input: ${input} returned: ${counter.countDPTopDown(input)}`)
160+
console.log(`Counter DP bottoms up for input: ${input} returned for ${counter.countDPBottomsUp(input)}`);
119161
}
120162

121163
testCountPalindromeSubstring("abdbca")

0 commit comments

Comments
 (0)