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:

  1. Base cases: Single characters (count = 1) and pairs (count = 2)
  2. Matching ends: When str[i] === str[j], we can form new palindromes by adding these characters to inner subsequences
  3. Non-matching ends: We take the union of palindromes from [i, j-1] and [i+1, j], minus their intersection
  4. 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.

Updated on: 2026-03-15T23:19:00+05:30

557 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements