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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy