Given a string s, find two disjoint palindromic subsequences of s such that the product of their lengths is maximized. The two subsequences are disjoint if they do not both pick a character at the same index.

Return the maximum possible product of the lengths of the two palindromic subsequences.

A subsequence is a string that can be derived from another string by deleting some or no characters without changing the order of the remaining characters. A string is palindromic if it reads the same forward and backward.

Input: s = "codingisfun"
Output: 9
Explanation: An optimal solution is to choose "igi" for the 1st subsequence and "nfn" for the 2nd subsequence.
The product of their lengths is: 3 * 3 = 9.
Example 1
Input: s = "bb"
Output: 1
Explanation: An optimal solution is to choose "b" (the first character) for the 1st subsequence and "b" (the second character) for the 2nd subsequence.
The product of their lengths is: 1 * 1 = 1.
Input: s = "accbcaxxcxx"
Output: 25
Explanation: An optimal solution is to choose "b" (the first character) for the 1st subsequence and "b" (the second character) for the 2nd subsequence.
The product of their lengths is: 1 * 1 = 1.
Constraints:

Contents

In this approach, we are going to generate pairs of all possible disjoint subsequences recursively and check if both are palindromes, if they are palindromes, then find product of maximum length palindromes among them.

Implementation steps:

public class MaxProductOfTwoDisjointPalindromes { /* Brute force approach using depth-first-search*/ static int maxProductUsingBruteForceApproach1_DFS(String s) { return dfs(s, 0, "", ""); } static int dfs(String s, int i, String s1, String s2) { if(i>= s.length()) { if(isPalindrome(s1) && isPalindrome(s2)) { return s1.length() * s2.length(); } return 0; } int left = dfs(s, i+1, s1+s.charAt(i), s2); int right = dfs(s, i+1, s1, s2+s.charAt(i)); int center = dfs(s, i+1, s1, s2); return Math.max(center, Math.max(left, right)); } static boolean isPalindrome(String input) { for(int i=0; i< input.length()/2; i++) { if(input.charAt(i) != input.charAt(input.length()-1 -i)) { return false; } } return true; } }
Complexity Analysis:

Time complexity: Above code runs in O(n * 3n) time where n is the length of input string s Since we are generating all possible subsequences using by calling dfs function recursively with 3 different inputs and this takes O (3n), and then checking whether the strings s1 and s2 are palindromes, that takes O (n)
Space complexity: O(3n), since we are making recursive calls, this space is being used by the stack memory.

This approach is also going to be a brute-force solution, but we will generate all possible subsequences using bit masking, meaning that when generating all possible subsequences, we will represent each character of input string s with either 1 or 0.

Let's understand with an example, say the given input string is s = "codingisfun", since there are 11 characters in input string, there are 2n-1 possible subsequences. So, using bit masking we can represent these using bit masking, the characters which we are using in the subsequence, we will put 1 in the same position as in input string position, to represent that we are using that particular character in subsequence. Below are few for example:

Implementation steps:
public class MaxProductOfTwoDisjointPalindromes { /* Brute force approach using Bit masking*/ static int maxProductUsingBruteForceApproach2_BitMasking(String s) { int mask = 1 <<s.length(); // all possible subsequences 2 power n int[] cache = new int[mask]; for (int i=1; i<mask ;i++) { // we are starting with i = 1 because bit-masking with all zeros doesn't represent // any subsequence String subSequence = ""; for(int j=0; j<s.length(); j++) { if( (i & (1 << j)) > 0) { // whether to include current character from j with mask being i subSequence += s.charAt(j); } } // now check subsequence reads same from both directions, for e.g. stats if(isPalindrome(subSequence)) { cache[i] = subSequence.length(); } } // since we have stored all possible palindromes and their length stored in dp array // now, find disjoint ones and max product among them int maxProduct = 0; for(int i=0; i<cache.length; i++) { for(int j=0; j<cache.length; j++) { if((i &j) ==0) { // disjoint indexes maxProduct = Math.max(maxProduct, cache[i] * cache[j]); } } } return maxProduct; } static boolean isPalindrome(String input) { for(int i=0; i< input.length()/2; i++) { if(input.charAt(i) != input.charAt(input.length()-1 -i)) { return false; } } return true; } }
Complexity Analysis:

Time complexity: Above code runs in O((2n * n) + n2) time where n is the length of input string s Since we are generating all possible subsequences using a for loop 2n -1 times, and checking each subsequence is a palindrome or not, this takes O(2n * n), then checking disjoint subsequences pair in nested loop, this takes O(n2).
Space complexity: O(n), since we are caching lengths of subsequences.

Above implementations source code can be found at GitHub link for Java code