Maximum Product Of The Length Of Two Palindromic Substrings

Solution For Maximum Product Of The Length Of Two Palindromic Substrings

Problem Statement:

Given a string s, find two palindromic substrings that are non-overlapping and the product of their lengths is maximum. Return the maximum product.

Constraints:

1 <= s.length <= 10^5
s consists of lowercase English letters only.

Solution:

In this problem, we are looking for two longest palindromic substrings that are non-overlapping.

The first step is to find all the palindromic substrings in the given string. We can use dynamic programming to achieve this. The idea is to maintain a 2D boolean array pal[i][j] which will be true if the substring s[i…j] is a palindrome.

Next, we will find two non-overlapping palindromic substrings and calculate their product of length. We can do this by iterating through all the palindromic substrings and finding two that are non-overlapping and have the maximum product.

Let’s discuss the implementation.

  • Step 1: Finding all the palindromic substrings
    We can use dynamic programming to maintain a 2D boolean array pal[i][j]. We can apply the following recurrence relation to fill up the array:
    pal[i][j] = s[i] == s[j] and pal[i + 1][j – 1].

We start with substrings of length 1 and 2. For every substring of length i, we calculate the boolean values for all substrings of length i+1.

The time complexity of this step is O(n^2) and the space complexity is O(n^2).

  • Step 2: Finding two non-overlapping palindromic substrings with maximum product
    We can use two nested loops to iterate through all the palindromic substrings and find two that are non-overlapping and have the maximum product of length.

The time complexity of this step is O(n^3) and the space complexity is O(1).

Overall, the time complexity of the solution is O(n^3) and the space complexity is O(n^2) which can be improved but is optimal for palindromic substring problems.

Code:

“`
class Solution {
public:
int maxProduct(string s) {
int n = s.size();
vector> pal(n, vector(n, false));

    // Step 1: Finding all the palindromic substrings
    for(int i=0; i<n; i++){
        pal[i][i] = true;
    }
    for(int i=0; i<n-1; i++){
        if(s[i] == s[i+1]){
            pal[i][i+1] = true;
        }
    }
    for(int i=n-3; i>=0; i--){
        for(int j=i+2; j<n; j++){
            if(s[i] == s[j] && pal[i+1][j-1]){
                pal[i][j] = true;
            }
        }
    }

    // Step 2: Finding two non-overlapping palindromic substrings with maximum product
    int ans = 0;
    for(int i=0; i<n; i++){
        for(int j=i+1; j<n; j++){
            if(pal[i][j]){
                for(int k=j+1; k<n; k++){
                    for(int l=k+1; l<n; l++){
                        if(pal[k][l]){
                            if((l-k+1)*(j-i+1) > ans && check(i, j, k, l)){
                                ans = (l-k+1)*(j-i+1);
                            }
                        }
                    }
                }
            }
        }
    }
    return ans;
}

bool check(int i, int j, int k, int l){
    if(i >= k && j <= l){
        return false;
    }
    if(k >= i && l <= j){
        return false;
    }
    return true;
}

};
“`

In this code, the function “check” checks if two palindromic substrings overlap. This is necessary because we only want to consider non-overlapping palindromic substrings.

Sample Input and Output:

Input: s = “ababa”
Output: 9
Explanation: The two palindromic substrings are “aba” and “aba”.

Input: s = “abb”
Output: 1
Explanation: The only palindromic substring is “bb”.

Step by Step Implementation For Maximum Product Of The Length Of Two Palindromic Substrings

public class Solution {
    public int maxProduct(String[] words) {
        if (words == null || words.length == 0)
            return 0;
        int len = words.length;
        
        int[] value = new int[len];
        for (int i = 0; i < len; i++) {
            String tmp = words[i];
            value[i] = 0;
            for (int j = 0; j < tmp.length(); j++) {
                value[i] |= 1 << (tmp.charAt(j) - 'a');
            }
        }
        int maxProduct = 0;
        for (int i = 0; i < len; i++)
            for (int j = i + 1; j < len; j++) {
                if ((value[i] & value[j]) == 0 && (words[i].length() * words[j].length() > maxProduct))
                    maxProduct = words[i].length() * words[j].length();
            }
        return maxProduct;
    }
}
def longestPalindrome(s): 
    n = len(s) 
  
    # Create a table to store results of subproblems 
    table = [[0 for x in range(n)] for y in range(n)] 
  
    # Strings of length 1 are palindromes 
    maxLength = 1
    i = 0
    while (i < n): 
        table[i][i] = True
        i = i + 1
  
    # Check for lengths 2, 3, ... , n 
    start = 0
    length = 2
    while (length <= n): 
  
        # For substring of length 2 
        if (length == 2): 
            i = 0
            while (i < n-1): 
                if (s[i] == s[i + 1]): 
                    table[i][i + 1] = True
                    start = i 
                    maxLength = length 
                i = i + 1
        # For lengths greater than 2 
        else: 
            i = 0
            while (i < n - length + 1): 
                j = i + length - 1
                if (table[i + 1][j - 1] and s[i] == s[j]): 
                    table[i][j] = True
  
                    if (length > maxLength): 
                        start = i 
                        maxLength = length 
                i = i + 1
        length = length + 1
    print("Longest palindrome substring is:") 
    print(s[start:start + maxLength]) 
  
    return maxLength
/**
 * @param {string} s
 * @return {number}
 */
var maxProduct = function(s) {
    let n = s.length,
        max = 0;
 
    // dp[i][j] is going to store the length of the
    // longest palindromic subsequence in substring
    // s[i..j]
    let dp = Array(n);
 
    // Fill dp[][] in bottom up manner
    for (let i = n - 1; i >= 0; i--) {
        dp[i] = Array(n);
        dp[i][i] = 1; // length of a palindrome subsequence of length 1 is 1
 
        for (let j = i + 1; j < n; j++) {
            // If the first and last characters are same
            if (s[i] == s[j]) {
                dp[i][j] = 2 + dp[i + 1][j - 1];
            } else {
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
 
        // update max if a palindromic subsequence
        // of length 2 or more is found
        if (dp[i][n - 1] > 1 && max < dp[i][n - 1] * dp[i][n - 1]) {
            max = dp[i][n - 1] * dp[i][n - 1];
        }
    }
 
    return max;
};
class Solution {
public:
    int maxProduct(string s) {
        int n = s.size();
        int max_len = 1; // The result (length of LPS)
 
        // Create a table to store results of subproblems
        int L[n][n];
 
        // Strings of length 1 are palindromes of length 1
        for (int i = 0; i < n; i++)
            L[i][i] = 1;
 
        // Build the table. Note that the lower diagonal values of table are
        // useless and not filled in the process. The values are filled in a
        // manner similar to Matrix Chain Multiplication DP solution (See
        // https://www.geeksforgeeks.org/matrix-chain-multiplication-dp-8/). Since
        // we need to find the length of longest palindromic substring, we find
        // the corresponding length information from table made by LCS
        // (https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/)
        // process.
        for (int cl=2; cl<=n; cl++)
        {
            for (int i=0; i max_len)
                    max_len = L[i][j];
            }
        }
        return max_len;
    }
};
public class Solution {
    public int MaxProduct(string s) {
        // maxProduct will keep track of the maximum product found so far
        int maxProduct = 0;
        
        // We will iterate through the string, keeping track of the start and end indices
        // of the longest palindrome found so far
        int start = 0;
        int end = 0;
        
        // We will also keep track of the longest palindrome found at each index
        // This will allow us to avoid recalculating the length of a palindrome
        // when we find one that contains a previously found palindrome
        int[] longestPalindromeAtIndex = new int[s.Length];
        
        for (int i = 0; i < s.Length; i++) {
            // We check if there is a palindrome centered at index i - 1
            // If there is, we can use the information stored in longestPalindromeAtIndex
            // to avoid recalculating the length of the palindrome
            if (i > 0 && longestPalindromeAtIndex[i - 1] > 0) {
                // We check if the palindrome centered at index i - 1
                // contains index i
                if (i + longestPalindromeAtIndex[i - 1] / 2 == i) {
                    // If it does, we check if the characters at indices i - 1 and i + 1
                    // are the same
                    if (s[i - 1] == s[i + 1]) {
                        // If they are, we update longestPalindromeAtIndex[i]
                        longestPalindromeAtIndex[i] = longestPalindromeAtIndex[i - 1] + 2;
                        
                        // We also update start and end if necessary
                        if (longestPalindromeAtIndex[i] > end - start) {
                            start = i - longestPalindromeAtIndex[i] / 2;
                            end = i + longestPalindromeAtIndex[i] / 2;
                        }
                    }
                }
            }
            // If there is no palindrome centered at index i - 1
            // or if the one centered at index i - 1 does not contain index i,
            // we check if there is a palindrome centered at index i
            else {
                // We check if the characters at indices i - 1 and i + 1 are the same
                if (s[i - 1] == s[i + 1]) {
                    // If they are, we update longestPalindromeAtIndex[i]
                    longestPalindromeAtIndex[i] = 3;
                    
                    // We also update start and end if necessary
                    if (longestPalindromeAtIndex[i] > end - start) {
                        start = i - longestPalindromeAtIndex[i] / 2;
                        end = i + longestPalindromeAtIndex[i] / 2;
                    }
                }
            }
            
            // We check if the palindrome centered at index i
            // contains index i + 1
            if (i + longestPalindromeAtIndex[i] / 2 == i + 1) {
                // If it does, we check if the characters at indices i and i + 2
                // are the same
                if (s[i] == s[i + 2]) {
                    // If they are, we update longestPalindromeAtIndex[i + 1]
                    longestPalindromeAtIndex[i + 1] = longestPalindromeAtIndex[i] + 2;
                    
                    // We also update start and end if necessary
                    if (longestPalindromeAtIndex[i + 1] > end - start) {
                        start = i + 1 - longestPalindromeAtIndex[i + 1] / 2;
                        end = i + 1 + longestPalindromeAtIndex[i + 1] / 2;
                    }
                }
            }
            
            // We update maxProduct if necessary
            if (longestPalindromeAtIndex[i] > maxProduct) {
                maxProduct = longestPalindromeAtIndex[i];
            }
        }
        
        return maxProduct;
    }
}


Top 100 Leetcode Practice Problems In Java

Get 30% Off Instantly!
[gravityforms id="5" description="false" titla="false" ajax="true"]