Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Counting all possible palindromic subsequence within a string in JavaScript
Palindrome Sequence
A palindromic subsequence is a sequence that reads the same from front and back. For instance, 'aba', 'madam', 'did' are all valid palindromic sequences. A subsequence can be contiguous or non-contiguous - we can skip characters but maintain their relative order.
We need to write a JavaScript function that counts all possible palindromic subsequences within a string. The input string contains only characters 'a', 'b', 'c', and 'd'.
Problem Example
For the string 'bccb', the palindromic subsequences are:
Input: "bccb" Palindromic subsequences: 'b', 'c', 'c', 'b', 'cc', 'bb', 'bcb', 'bccb' Total count: 6
Algorithm Approach
We use dynamic programming with a 2D table where dp[i][j] represents the count of palindromic subsequences in substring from index i to j. The approach handles three cases:
- If characters at ends match: we can form new palindromes
- If they don't match: we exclude one end and sum the results
- Handle overlapping counts to avoid duplication
Implementation
const countPalindromes = (str = '') => {
let base = 1000000007;
const n = str.length;
// Initialize 2D DP array
const dp = Array(n).fill(null).map(() => Array(n).fill(0));
// Fill the DP table
for (let l = 1; l <= n; l++) {
for (let i = 0; i + l - 1 < n; i++) {
let j = i + l - 1;
if (l === 1) {
dp[i][j] = 1; // Single character is palindrome
continue;
}
if (l === 2) {
dp[i][j] = 2; // Two characters form 2 palindromes
continue;
}
if (str[i] === str[j]) {
// Characters match - find duplicates in between
let left = i + 1, right = j - 1;
while (left <= right && str[left] !== str[i]) {
left++;
}
while (left <= right && str[right] !== str[i]) {
right--;
}
if (left > right) {
// No matching characters in between
dp[i][j] = dp[i + 1][j - 1] * 2 + 2;
} else if (left === right) {
// One matching character
dp[i][j] = dp[i + 1][j - 1] * 2 + 1;
} else {
// Multiple matching characters - subtract overlaps
dp[i][j] = dp[i + 1][j - 1] * 2 - dp[left + 1][right - 1];
}
} else {
// Characters don't match
dp[i][j] = dp[i][j - 1] + dp[i + 1][j] - dp[i + 1][j - 1];
}
// Handle negative values and modulo
dp[i][j] = dp[i][j] < 0 ? dp[i][j] + base : dp[i][j] % base;
}
}
return dp[0][n - 1];
};
// Test the function
const str = 'bccb';
console.log(`Input: "${str}"`);
console.log(`Palindromic subsequences count: ${countPalindromes(str)}`);
Input: "bccb" Palindromic subsequences count: 6
How It Works
The algorithm uses a bottom-up dynamic programming approach:
- Base cases: Single characters (count = 1) and pairs (count = 2)
- Matching ends: When str[i] === str[j], we can form new palindromes by adding these characters to inner subsequences
- Non-matching ends: We take the union of palindromes from [i, j-1] and [i+1, j], minus their intersection
- Duplicate handling: When ends match, we check for duplicate characters to avoid overcounting
Time and Space Complexity
Time Complexity: O(n³) where n is the string length, due to the nested loops and character searching.
Space Complexity: O(n²) for the 2D DP table.
Conclusion
This dynamic programming solution efficiently counts palindromic subsequences by building up results from smaller subproblems. The algorithm handles character duplicates and uses modular arithmetic to prevent integer overflow for large results.
