Maximum Product of The Length of Two Palindromic Subsequences
Given a string ss
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.
Example 1
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 2
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.
Example 3
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 consists of lowercase English letters onlys
Contents
Solution 1 - Generate all possible subsequences recursively using DFS, 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
ands1 and initialize them with empty strings to start withs2 ."" -
Then, we will generate pairs of disjoint subsequences by doing this:
-
Add character at
position from input string toith , without changings1 .s2 -
Add character at
position from input string toith , without changings2 .s1 -
Without adding any characters, take
ands1 as is from previous inputs.s2
.s
For example, consider input string
s = "codingisfun"
Initially ands1 =""s2 = ""
Then, we take 1st character from input string, which is , now we will generate subsequence pairc ands1 = "c" remains same. Next, add same character tos2 ="" ands2 remains unchanged,s1 ands1 = ""s2 ="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
ands1 are palindromes then return their lengths product.s2 -
When we call above procedure, for three different inputs, we will get theree results.
-
being appended with new characters,s1 remains same, call the result ass2 .left -
being appended with new characters,s2 remains same, call the result ass1 .right -
ands1 remains unchanged with disjoint pair of subsequences passed originally to recursive function, before adding characters to eithers2 ors1 , call the result ass2 .center
-
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 nsdfss1s2
Space complexity: O(3n), since we are making recursive calls, this space is being used by the stack memory.
Solution 2 - Generate all possible subsequences using bit masking, then find max length product of disjoint subsequences
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 s10
Let's understand with an example, say the given input string is s = "codingisfun"2n-11
- 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
loop, going fromfor =i to1 , then for each of the number in this loop, we need to find out which characters that we are going to consider. For example if2n-1 we will need to get only the first character from input stringi =1 , so we will use another loop froms =j , then perform bitwise operation0...., s.length() to know which character need to be considered fori & (1 < < j) > 0 subsequence, let's break it down why we are using this bitwise operation. (If you need to refresh BitWise operations, take a look atithBitwise Operators )-
Left shift bitwise operator,
creates a mask with the(1 << j) bit set to 1 (wherejth ranges from 0 to N-1). For example, it generates masks by moving 1 bit to left side...j ,00000000001 , so on until00000000010 .10000000000 -
performs a bitwise AND operation between the numberi & (1 << j) and the maski , and if the result is non-zero, it means it means that the(1 << j) bit in i is set tojth , indicating that the character at position1 should be included in the current subsequence being generated.j
-
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
) with position ascache .i -
Now, finally loop through
in a nested loop, since we need to find out disjoint subsequences, to find such unique subsequences, we can use logical AND (cache ) on the indices of nested loops, and check if the result is 0& , this means that they have biti & j == 0 in different positions, so they are disjoint subsequences, so compute the product of their lengths and keep track of maximum value.1
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 nsfor2n -1
Space complexity: O(n), since we are caching lengths of subsequences.
Above implementations source code can be found at