Given a string
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.
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.

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.
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:
2 <= s.length <= 12 s consists of lowercase English letters only
Contents
Solution 1 - Generate all possible subsequences recursively using DFS, then find max length product of disjoint subsequences Solution 2 - Generate all possible subsequences using bit masking, then find max length product of disjoint subsequences
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:
-
In this implementation, we will use two variables
s1 ands2 and initialize them with empty strings to start with"" . -
Then, we will generate pairs of disjoint subsequences by doing this:
-
Add character at
ith position from input string tos1 , without changings2 . -
Add character at
ith position from input string tos2 , without changings1 . -
Without adding any characters, take
s1 ands2 as is from previous inputs.
s .
For example, consider input string
s = "codingisfun"
Initiallys1 ="" ands2 = ""
Then, we take 1st character from input string, which isc , now we will generate subsequence pairs1 = "c" ands2 ="" remains same. Next, add same character tos2 ands1 remains unchanged,s1 = "" ands2 ="c"
We will repeat this for all combinations of characters by recursively calling this procedure.
-
Add character at
-
Base case for this recursive function is when we reach end of input string, we will check if
s1 ands2 are palindromes then return their lengths product. -
When we call above procedure, for three different inputs, we will get theree results.
-
s1 being appended with new characters,s2 remains same, call the result asleft . -
s2 being appended with new characters,s1 remains same, call the result asright . -
s1 ands2 remains unchanged with disjoint pair of subsequences passed originally to recursive function, before adding characters to eithers1 ors2 , call the result ascenter .
-
Complexity Analysis:
Time complexity: Above code runs in O(n * 3n) time where
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
Let's understand with an example, say the given input string is
- c =>
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
. - code =>
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
. - o =>
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
. - ode =>
0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
. - codeingisfun =>
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
.
Implementation steps:
-
We will generate all possible subsequences using a
for loop, going fromi =1 to2n-1 , then for each of the number in this loop, we need to find out which characters that we are going to consider. For example ifi =1 we will need to get only the first character from input strings , so we will use another loop fromj =0...., s.length() , then perform bitwise operationi & (1 < < j) > 0 to know which character need to be considered forith subsequence, let's break it down why we are using this bitwise operation. (If you need to refresh BitWise operations, take a look atBitwise Operators )-
Left shift bitwise operator,
(1 << j) creates a mask with thejth bit set to 1 (wherej ranges from 0 to N-1). For example, it generates masks by moving 1 bit to left side...00000000001 ,00000000010 , so on until10000000000 . -
i & (1 << j) performs a bitwise AND operation between the numberi and the mask(1 << j) , and if the result is non-zero, it means it means that thejth bit in i is set to1 , indicating that the character at positionj should be included in the current subsequence being generated.
-
Left shift bitwise operator,
-
While generating subsequences, we will also check if the subsequence is a palindrome, if it is a palindrome then cache its length into an array (call it
cache ) with position asi . -
Now, finally loop through
cache in a nested loop, since we need to find out disjoint subsequences, to find such unique subsequences, we can use logical AND (& ) on the indices of nested loops, and check if the result is 0i & j == 0 , this means that they have bit1 in different positions, so they are disjoint subsequences, so compute the product of their lengths and keep track of maximum value.
Complexity Analysis:
Time complexity: Above code runs in O((2n * n) + n2) time where
Space complexity: O(n), since we are caching lengths of subsequences.
Above implementations source code can be found at