1771. Maximize Palindrome Length From Subsequences
Problem Description
In this problem, we are tasked with creating the longest palindrome possible by concatenating a subsequence from word1
with a subsequence from word2
. A subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements. A palindrome is a word or phrase that reads the same backwards as forwards.
The goal is to figure out the length of the longest palindrome that can be formed in this way. If it's not possible to create any palindrome, the result should be 0. It is important to note that subsequence1 and subsequence2 must both be non-empty.
Intuition
To arrive at the solution, we have to consider that a palindrome reads the same forwards and backwards. Therefore, we need to look for matching characters in word1
and word2
. Since we can form subsequences, we are not restricted to contiguous characters and we can skip some in order to maximize the length of the palindrome.
The idea is to concatenate word1
and word2
into one string and then apply a dynamic programming approach to find the longest palindrome subsequence. The dynamic programming (DP) solution uses a 2D table f
where f[i][j]
represents the length of the longest palindromic subsequence between index i
and j
in the concatenated string s
. We initialize this table with zeros and fill it in a way that each cell f[i][j]
takes into account the characters at s[i]
and s[j]
. If they match and belong to different parts (one from word1
and the other from word2
), we can increase the length of a valid palindrome by 2. We iterate through the string in a manner such that we solve smaller subproblems first, which then can be used to construct solutions for larger subproblems.
While filling the DP table, we keep an eye out for the characters that come from the point where word1
ends and word2
begins. If s[i]
and s[j]
match and i
belongs to word1
while j
belongs to word2
, it implies that we have a palindrome that uses characters from both words. This is when we update our answer (ans
), which keeps track of the maximum length found so far.
In summary, the solution approach consists of the following steps:
- Concatenate
word1
andword2
. - Initialize a DP table to store the length of the longest palindromic subsequence.
- Update the table according to the matching characters in the string.
- Keep track of the maximum length whenever characters in
word1
andword2
contribute to the palindrome. - Return the maximum length recorded.
Learn more about Dynamic Programming patterns.
Solution Approach
The solution is accomplished by applying dynamic programming (DP), which is an algorithmic technique used to solve problems by breaking them down into subproblems, solving each subproblem only once, and storing their solutions.
Here's a step-by-step explanation of the implementation:
-
Concatenating the Strings: The first step is to concatenate
word1
andword2
into a single strings
. -
Initializing the DP Table: A 2D DP table
f
is initialized with dimensionsn x n
, wheren
is the length of the concatenated strings
. Each cellf[i][j]
in this table will eventually contain the length of the longest palindromic subsequence between indicesi
andj
. For single characters, which can be considered as the shortest palindromes, the diagonalf[i][i]
is filled with1
. -
Bottom-Up DP Computation: The table is filled in a bottom-up manner. The loops are arranged to have
i
decrease fromn-1
to0
andj
increase fromi+1
ton-1
. This ensures that before we try to computef[i][j]
, the subproblemsf[i+1][j-1]
,f[i+1][j]
, andf[i][j-1]
are already computed. -
Updating the DP Table:
-
Case When Characters Match: If
s[i]
matchess[j]
, it means that characters at these indices can potentially form or extend a palindrome. Therefore, we setf[i][j] = f[i+1][j-1] + 2
. The termf[i+1][j-1]
represents the length of the longest palindromic subsequence within the substring that excludes the current matching characters that are just added to the ends of the palindrome. The addition of2
accounts for the two matching characters. -
Checking the Words' Boundaries: If the matching characters are such that
s[i]
is inword1
ands[j]
is inword2
, it indicates the formation of a palindrome using parts of bothword1
andword2
. Thus, the current palindrome lengthf[i][j]
is compared with the maximum length found so far, and if it's larger,ans
is updated. -
Case When Characters Don't Match: If
s[i]
does not matchs[j]
, then the longest palindrome atf[i][j]
is the maximum of the longest palindromic subsequences found by either includings[i]
and excludings[j]
(f[i+1][j]
), or excludings[i]
and includings[j]
(f[i][j-1]
). Essentially, this step omits one of the mismatching characters and looks at the best result achieved by the remaining string.
-
-
Returning the Result: The variable
ans
keeps track of the maximum length of a palindrome that can be constructed by using the aforementioned rules. After the loops are finished,ans
contains the length of the longest palindrome possible, and that is what is returned by the function.
By employing this DP approach, we can efficiently compute the longest palindromic sequence that can be constructed from word1
and word2
by reusing solutions to subproblems and building up to the final solution.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's say we have word1 = "abaxy"
and word2 = "azby"
and we want to find the length of the longest palindrome that can be formed by concatenating subsequences of these two words.
Following the steps of the solution:
-
Concatenating the Strings: By concatenating
word1
andword2
, we gets = "abaxyazby"
. -
Initializing the DP Table: We create a 2D table
f
with dimensions 10 x 10, ass
has a length of 10. -
Bottom-Up DP Computation: We traverse the table by starting from the end of
s
and working backwards, ensuring that the substring problems are solved first. -
Updating the DP Table:
- As we iterate over the table, we check for every pair
s[i]
ands[j]
. - For
i = 4
(the last character ofword1
) andj = 5
(the first character ofword2
):- We note that
s[i] = y
ands[j] = a
do not match, sof[4][5]
will be the max off[5][5]
andf[4][4]
, which are both 1, sof[4][5] = 1
.
- We note that
- Continuing the process:
- For
i = 1
andj = 8
, we see thats[i] = b
ands[j] = b
do match. Therefore, we setf[1][8] = f[2][7] + 2
. Assumef[2][7]
was already computed and is 1, sof[1][8] = 1 + 2 = 3
. This is a valid palindrome consisting of the substrings "b" fromword1
and "b" fromword2
.
- For
- We continue filling out the table in this manner, looking for matches and updating the length of potential palindromes accordingly.
- As we iterate over the table, we check for every pair
-
Returning the Result: Assume after iterating through the entire table and considering all possible subsequence pairs, the maximum length recorded in our
ans
is 3 (from the palindrome "aba" or "bab"). This means the longest palindrome that can be formed by concatenating subsequences fromword1
andword2
is of length 3.
In this example, the steps have given us a systematic approach to finding matches between two words and using these to find a palindrome by employing dynamic programming to avoid redundant calculations.
Solution Implementation
1class Solution:
2 def longestPalindrome(self, word1: str, word2: str) -> int:
3 # Concatenate both strings to find palindromes across them.
4 concatenated_word = word1 + word2
5 total_length = len(concatenated_word)
6
7 # Initialize the DP table where dp_table[i][j] will represent
8 # the longest palindromic subsequence's length in the substring concatenated_word[i..j].
9 dp_table = [[0] * total_length for _ in range(total_length)]
10
11 # Every single character is a palindrome of length 1.
12 for i in range(total_length):
13 dp_table[i][i] = 1
14
15 # Answer to maintain the maximum length of palindromic subsequence
16 # which starts in word1 and ends in word2.
17 max_length = 0
18
19 # Fill out the table
20 # Start from the end of the string and compare characters.
21 for i in range(total_length - 1, -1, -1):
22 for j in range(i + 1, total_length):
23 # If characters match, add 2 to the length of the palindrome
24 # (since 'i' and 'j' are the same, they make a pair).
25 if concatenated_word[i] == concatenated_word[j]:
26 dp_table[i][j] = dp_table[i + 1][j - 1] + 2
27
28 # If the palindrome starts in the first word and ends in the second word,
29 # update the max palindrome length.
30 if i < len(word1) and j >= len(word1):
31 max_length = max(max_length, dp_table[i][j])
32 else:
33 # If the characters don't match, propagate the max length so far.
34 dp_table[i][j] = max(dp_table[i + 1][j], dp_table[i][j - 1])
35
36 return max_length
37
1class Solution {
2 public int longestPalindrome(String word1, String word2) {
3 // Combine both words to create one string
4 String combined = word1 + word2;
5 int length = combined.length();
6
7 // Create a memoization table to store lengths of palindromic subsequences
8 int[][] dpTable = new int[length][length];
9
10 // Every single character is a palindrome of length 1
11 for (int i = 0; i < length; ++i) {
12 dpTable[i][i] = 1;
13 }
14
15 int maxPalindromeLength = 0; // This will store the length of the longest palindrome
16
17 // Fill the memoization table with lengths of longest palindromic subsequences
18 for (int i = length - 2; i >= 0; --i) {
19 for (int j = i + 1; j < length; ++j) {
20 // If characters at current positions in the string are the same
21 if (combined.charAt(i) == combined.charAt(j)) {
22 // Increment the length by 2 (plus the length of the palindrome in between the current characters)
23 dpTable[i][j] = dpTable[i + 1][j - 1] + 2;
24
25 // Check if the current palindrome includes characters from both word1 and word2
26 if (i < word1.length() && j >= word1.length()) {
27 // Update maxPalindromeLength if the current one is the longest so far
28 maxPalindromeLength = Math.max(maxPalindromeLength, dpTable[i][j]);
29 }
30 } else {
31 // Choose the longer palindrome obtained either by excluding the current char from word1 or word2
32 dpTable[i][j] = Math.max(dpTable[i + 1][j], dpTable[i][j - 1]);
33 }
34 }
35 }
36
37 // Return the length of the longest palindrome which includes characters from both word1 and word2
38 return maxPalindromeLength;
39 }
40}
41
1#include <vector>
2#include <string>
3#include <cstring>
4#include <algorithm>
5
6using namespace std;
7
8class Solution {
9public:
10 // Function to find the longest palindrome that can be created using the concatenation of word1 and word2
11 int longestPalindrome(string word1, string word2) {
12 // Combine the two strings
13 string combined = word1 + word2;
14
15 // Get the length of the combined string
16 int length = combined.size();
17
18 // Create a 2D array to store the longest palindromic subsequence length
19 vector<vector<int>> dp(length, vector<int>(length, 0));
20
21 // A single letter is a palindrome of length 1
22 for (int i = 0; i < length; ++i)
23 dp[i][i] = 1;
24
25 // Initialize the variable to store the result
26 int longest = 0;
27
28 // Fill the dp array bottom-up
29 for (int i = length - 2; i >= 0; --i) {
30 for (int j = i + 1; j < length; ++j) {
31 // If the characters match, add 2 to the value from the diagonal
32 if (combined[i] == combined[j]) {
33 dp[i][j] = dp[i + 1][j - 1] + 2;
34 // If string is such that 'i' is from word1 and 'j' is from word2
35 // Update the longest palindrome
36 if (i < word1.size() && j >= word1.size()) {
37 longest = max(longest, dp[i][j]);
38 }
39 } else {
40 // If the characters don't match, take the max of skipping either character
41 dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
42 }
43 }
44 }
45
46 // Return the length of the longest palindrome
47 return longest;
48 }
49};
50
1// Importing necessary functionality for using arrays.
2// TypeScript has no standard library like C++, so here we are just using basic arrays.
3function longestPalindrome(word1: string, word2: string): number {
4 // Combine the two strings
5 const combined: string = word1 + word2;
6
7 // Get the length of the combined string
8 const length: number = combined.length;
9
10 // Create a 2D array to store the longest palindromic subsequence length
11 const dp: number[][] = Array.from({ length }, () => Array(length).fill(0));
12
13 // A single letter is a palindrome of length 1
14 for (let i = 0; i < length; ++i)
15 dp[i][i] = 1;
16
17 // Initialize the variable to store the maximum length of a palindrome
18 let maxPalindromeLength: number = 0;
19
20 // Fill the dp array from bottom to top
21 for (let i = length - 2; i >= 0; --i) {
22 for (let j = i + 1; j < length; ++j) {
23 // If the characters match, add 2 to the value from the diagonal
24 if (combined[i] === combined[j]) {
25 dp[i][j] = dp[i + 1][j - 1] + 2;
26
27 // If 'i' is from word1 and 'j' is from word2, update maxPalindromeLength
28 if (i < word1.length && j >= word1.length) {
29 maxPalindromeLength = Math.max(maxPalindromeLength, dp[i][j]);
30 }
31 } else {
32 // If the characters don't match, take the maximum of skipping either character
33 dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
34 }
35 }
36 }
37
38 // Return the length of the longest palindrome
39 return maxPalindromeLength;
40}
41
Time and Space Complexity
Time Complexity
The function longestPalindrome
uses dynamic programming to solve the problem of finding the longest palindromic subsequence that can be formed using the concatenation of word1
and word2
. The time complexity can be analyzed as follows:
- There is a nested loop structure where the outer loop runs for
n
times, wheren
is the length of the concatenated strings
(that is,n = len(word1) + len(word2)
). The inner loop also runs forn
times, although not all iterations are full due to the starting point of the inner loop depending on the outer loop. - In each iteration, operations are performed with constant time complexity, specifically: assignment, comparison, and arithmetic operations.
Therefore, the total time complexity is O(n^2)
, where n
is the length of the concatenated string s
.
Space Complexity
The space complexity of the function can be determined as follows:
- A 2D list
f
of sizen * n
is created to store the lengths of palindromic subsequences, wheren
is the length of the strings
. Each cell of the list stores a single integer. - Constant space is used for variables like
i
,j
,ans
, and for some temporary variables used during comparisons and assignments.
As the dominant space requirement is the 2D list f
, the space complexity is O(n^2)
, where n
is the length of the concatenated string s
.
Learn more about how to find time and space complexity quickly using problem constraints.
How does quick sort divide the problem into subproblems?
Recommended Readings
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!