3504. Longest Palindrome After Substring Concatenation II
Problem Description
You are given two strings s
and t
.
You need to find the longest possible palindrome that can be created by:
- Selecting a substring from
s
(which can be empty) - Selecting a substring from
t
(which can be empty) - Concatenating them in that order (substring from
s
followed by substring fromt
)
The task is to return the length of the longest palindrome that can be formed this way.
For example, if you have strings s
and t
, you could:
- Use only a palindromic substring from
s
(leavingt
's contribution empty) - Use only a palindromic substring from
t
(leavings
's contribution empty) - Use a substring from
s
concatenated with a substring fromt
that together form a palindrome
The key insight is that when concatenating substrings from both strings to form a palindrome, the ending portion of the substring from s
must match (in reverse) with the beginning portion of the substring from t
. This creates a palindromic structure where the first part mirrors the second part.
The solution approach involves:
- Preprocessing both strings to find all palindromic substrings starting at each position
- Using dynamic programming to find matching sequences between
s
and the reverse oft
- Considering cases where additional palindromic content exists in either string beyond the matching portion
- Tracking the maximum palindrome length across all possible combinations
Intuition
To understand how to build the longest palindrome from two strings, let's think about what palindromes look like when formed from concatenated substrings.
A palindrome reads the same forwards and backwards. When we concatenate a substring from s
with a substring from t
, we get three possible scenarios:
-
The palindrome comes entirely from one string: We simply need to find the longest palindromic substring in either
s
ort
. -
The palindrome spans both strings: This is the interesting case. For the concatenated result to be a palindrome, the end of the substring from
s
must mirror the beginning of the substring fromt
.
Think of it this way: if we have "abc" from s
and "cba" from t
, concatenating gives us "abccba" - a palindrome! The key observation is that the substring from t
needs to be the reverse of the substring from s
for the concatenation to form a palindrome.
This leads us to reverse string t
first. Now, finding matching parts between s
and reversed t
becomes a problem of finding common substrings, which we can solve with dynamic programming. When s[i] == reversed_t[j]
, we can extend our palindrome.
But there's another layer: what if after matching some characters between s
and reversed t
, there's still a palindromic tail in s
or a palindromic head in reversed t
? For example, if we match "ab" from s
with "ba" from reversed t
to get "abba", but s
actually has "abcbc" where "cbc" is also a palindrome, we can include it to get "abcbcba"!
This is why we precompute g1[i]
and g2[j]
- they tell us the longest palindrome starting at position i
in s
and position j
in reversed t
respectively. After finding matching portions with DP, we check if we can extend the palindrome further using these precomputed values.
The formula f[i][j] * 2 + g1[i]
represents: the matched portion doubled (since it appears in both halves of the palindrome) plus any additional palindromic content that can be added from the middle outward.
Learn more about Two Pointers and Dynamic Programming patterns.
Solution Approach
The implementation consists of three main components: preprocessing palindromes, reversing string t
, and dynamic programming to find the longest palindrome.
Step 1: Preprocessing Palindromic Substrings
The calc
function finds the longest palindromic substring starting at each position. It uses the expand
helper function to check palindromes by expanding from centers:
- For each position
i
, we try two types of centers:- Odd-length palindromes: expand from
(i, i)
- Even-length palindromes: expand from
(i, i+1)
- Odd-length palindromes: expand from
- The
expand
function updatesg[l]
with the maximum palindrome length starting at positionl
def expand(s: str, g: List[int], l: int, r: int):
while l >= 0 and r < len(s) and s[l] == s[r]:
g[l] = max(g[l], r - l + 1)
l, r = l - 1, r + 1
Step 2: Reverse String t
and Initialize
We reverse string t
because we need to find matching sequences between the end of substring from s
and the beginning of substring from t
:
t = t[::-1]
g1, g2 = calc(s), calc(t)
ans = max(*g1, *g2) # Initialize with longest palindrome from single string
Step 3: Dynamic Programming for Matching Sequences
We create a 2D DP table f[i][j]
where f[i][j]
represents the length of matching sequence ending at position i-1
in s
and position j-1
in reversed t
:
f = [[0] * (n + 1) for _ in range(m + 1)]
for i, a in enumerate(s, 1):
for j, b in enumerate(t, 1):
if a == b:
f[i][j] = f[i - 1][j - 1] + 1
When characters match (a == b
), we extend the matching sequence by 1.
Step 4: Calculate Maximum Palindrome Length
For each matching position, we consider two cases for extending the palindrome:
-
Extend with remaining palindrome from
s
:ans = max(ans, f[i][j] * 2 + (0 if i >= m else g1[i]))
f[i][j] * 2
: The matched portion appears twice (once froms
, once from reversedt
)g1[i]
: Additional palindrome starting from positioni
ins
(if not at end)
-
Extend with remaining palindrome from reversed
t
:ans = max(ans, f[i][j] * 2 + (0 if j >= n else g2[j]))
- Similar logic but using
g2[j]
for the palindrome in reversedt
- Similar logic but using
The final answer is the maximum palindrome length found across all possibilities.
Time Complexity: O(m*n)
where m
and n
are lengths of strings s
and t
Space Complexity: O(m*n)
for the DP table
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with s = "abcd"
and t = "dcba"
.
Step 1: Preprocess palindromic substrings
For s = "abcd"
:
- Position 0 ('a'): longest palindrome starting here = 1 ("a")
- Position 1 ('b'): longest palindrome starting here = 1 ("b")
- Position 2 ('c'): longest palindrome starting here = 1 ("c")
- Position 3 ('d'): longest palindrome starting here = 1 ("d")
So
g1 = [1, 1, 1, 1]
For t = "dcba"
:
- Position 0 ('d'): longest palindrome starting here = 1 ("d")
- Position 1 ('c'): longest palindrome starting here = 1 ("c")
- Position 2 ('b'): longest palindrome starting here = 1 ("b")
- Position 3 ('a'): longest palindrome starting here = 1 ("a")
So
g2_original = [1, 1, 1, 1]
Step 2: Reverse string t
After reversing: t = "abcd"
(reversed from "dcba")
Now g2 = [1, 1, 1, 1]
(positions correspond to reversed string)
Initialize ans = 1
(maximum from single character palindromes)
Step 3: Build DP table for matching sequences
We build f[i][j]
where f[i][j]
represents length of matching sequence ending at s[i-1]
and t[j-1]
:
"" a b c d (reversed t) "" 0 0 0 0 0 a 0 1 0 0 0 b 0 0 2 0 0 c 0 0 0 3 0 d 0 0 0 0 4 (s)
Key matches:
f[1][1] = 1
: "a" matches "a"f[2][2] = 2
: "ab" matches "ab"f[3][3] = 3
: "abc" matches "abc"f[4][4] = 4
: "abcd" matches "abcd"
Step 4: Calculate maximum palindrome
For each non-zero f[i][j]
, we check:
At f[1][1] = 1
(matched "a" from s and "a" from reversed t):
- Case 1:
1 * 2 + g1[1] = 2 + 1 = 3
(palindrome: "aba") - Case 2:
1 * 2 + g2[1] = 2 + 1 = 3
(palindrome: "aba") - Update
ans = 3
At f[2][2] = 2
(matched "ab" from s and "ab" from reversed t):
- Case 1:
2 * 2 + g1[2] = 4 + 1 = 5
(palindrome: "abcba") - Case 2:
2 * 2 + g2[2] = 4 + 1 = 5
(palindrome: "abcba") - Update
ans = 5
At f[3][3] = 3
(matched "abc" from s and "abc" from reversed t):
- Case 1:
3 * 2 + g1[3] = 6 + 1 = 7
(palindrome: "abcdcba") - Case 2:
3 * 2 + g2[3] = 6 + 1 = 7
(palindrome: "abcdcba") - Update
ans = 7
At f[4][4] = 4
(matched "abcd" from s and "abcd" from reversed t):
- Case 1:
4 * 2 + 0 = 8
(i >= m, so no more characters in s) - Case 2:
4 * 2 + 0 = 8
(j >= n, so no more characters in reversed t) - Update
ans = 8
Final Result: 8
The longest palindrome is "abcddcba" formed by taking "abcd" from s
and "dcba" from t
.
Solution Implementation
1class Solution:
2 def longestPalindrome(self, s: str, t: str) -> int:
3 """
4 Find the longest palindrome that can be formed by concatenating parts of strings s and t.
5 The palindrome can be formed by:
6 1. A palindrome from s alone
7 2. A palindrome from t alone
8 3. A prefix from s + suffix from reversed t (forming a palindrome)
9 """
10
11 def expand_around_center(string: str, palindrome_lengths: List[int], left: int, right: int) -> None:
12 """
13 Expand around center to find palindromes and update the maximum palindrome length
14 starting at each position.
15
16 Args:
17 string: The input string
18 palindrome_lengths: Array storing max palindrome length starting at each index
19 left: Left pointer for expansion
20 right: Right pointer for expansion
21 """
22 while left >= 0 and right < len(string) and string[left] == string[right]:
23 # Update the maximum palindrome length starting at position 'left'
24 palindrome_lengths[left] = max(palindrome_lengths[left], right - left + 1)
25 left -= 1
26 right += 1
27
28 def calculate_palindrome_lengths(string: str) -> List[int]:
29 """
30 Calculate the maximum palindrome length starting at each position in the string.
31
32 Args:
33 string: Input string
34
35 Returns:
36 List where palindrome_lengths[i] = max palindrome length starting at index i
37 """
38 n = len(string)
39 palindrome_lengths = [0] * n
40
41 for i in range(n):
42 # Check for odd-length palindromes (single character center)
43 expand_around_center(string, palindrome_lengths, i, i)
44 # Check for even-length palindromes (two character center)
45 expand_around_center(string, palindrome_lengths, i, i + 1)
46
47 return palindrome_lengths
48
49 # Get lengths of input strings
50 m, n = len(s), len(t)
51
52 # Reverse string t for easier computation
53 t_reversed = t[::-1]
54
55 # Calculate max palindrome lengths starting at each position
56 palindrome_lengths_s = calculate_palindrome_lengths(s)
57 palindrome_lengths_t_reversed = calculate_palindrome_lengths(t_reversed)
58
59 # Initialize answer with the longest palindrome from either string alone
60 max_palindrome_length = max(*palindrome_lengths_s, *palindrome_lengths_t_reversed)
61
62 # dp[i][j] represents the length of longest common prefix between s[0:i] and t_reversed[0:j]
63 # This helps find matching prefixes and suffixes that can form palindromes
64 dp = [[0] * (n + 1) for _ in range(m + 1)]
65
66 # Fill the DP table
67 for i, char_s in enumerate(s, 1):
68 for j, char_t_reversed in enumerate(t_reversed, 1):
69 if char_s == char_t_reversed:
70 # Extend the common prefix length
71 dp[i][j] = dp[i - 1][j - 1] + 1
72
73 # Try forming palindrome: prefix from s + suffix from t + remaining palindrome from s
74 if i < m: # Check if there are remaining characters in s
75 candidate_length = dp[i][j] * 2 + palindrome_lengths_s[i]
76 max_palindrome_length = max(max_palindrome_length, candidate_length)
77 else:
78 # No remaining characters, just the matched prefix and suffix
79 max_palindrome_length = max(max_palindrome_length, dp[i][j] * 2)
80
81 # Try forming palindrome: prefix from s + suffix from t + remaining palindrome from t_reversed
82 if j < n: # Check if there are remaining characters in t_reversed
83 candidate_length = dp[i][j] * 2 + palindrome_lengths_t_reversed[j]
84 max_palindrome_length = max(max_palindrome_length, candidate_length)
85 else:
86 # No remaining characters, just the matched prefix and suffix
87 max_palindrome_length = max(max_palindrome_length, dp[i][j] * 2)
88
89 return max_palindrome_length
90
1class Solution {
2 /**
3 * Finds the longest palindrome that can be formed by concatenating a prefix of string S
4 * with a suffix of string T.
5 *
6 * @param S first string
7 * @param T second string
8 * @return length of the longest palindrome
9 */
10 public int longestPalindrome(String S, String T) {
11 // Convert strings to character arrays for easier manipulation
12 char[] sArray = S.toCharArray();
13 // Reverse T to convert suffix matching to prefix matching
14 char[] tArrayReversed = new StringBuilder(T).reverse().toString().toCharArray();
15
16 int sLength = sArray.length;
17 int tLength = tArrayReversed.length;
18
19 // Calculate the longest palindrome starting at each position for both strings
20 int[] palindromeLengthsFromS = calculatePalindromeLengths(sArray);
21 int[] palindromeLengthsFromT = calculatePalindromeLengths(tArrayReversed);
22
23 // Initialize answer with the longest palindrome from either string alone
24 int maxPalindromeLength = Math.max(
25 Arrays.stream(palindromeLengthsFromS).max().getAsInt(),
26 Arrays.stream(palindromeLengthsFromT).max().getAsInt()
27 );
28
29 // DP table where dp[i][j] represents the length of common prefix
30 // between sArray[0...i-1] and tArrayReversed[0...j-1]
31 int[][] dp = new int[sLength + 1][tLength + 1];
32
33 // Fill the DP table
34 for (int i = 1; i <= sLength; ++i) {
35 for (int j = 1; j <= tLength; ++j) {
36 // If characters match, extend the common prefix
37 if (sArray[i - 1] == tArrayReversed[j - 1]) {
38 dp[i][j] = dp[i - 1][j - 1] + 1;
39
40 // Case 1: Use prefix from S + suffix from T + remaining palindrome from S
41 // The total length is: common prefix/suffix * 2 + palindrome starting after prefix in S
42 if (i < sLength) {
43 maxPalindromeLength = Math.max(maxPalindromeLength,
44 dp[i][j] * 2 + palindromeLengthsFromS[i]);
45 }
46
47 // Case 2: Use prefix from S + suffix from T + remaining palindrome from T
48 // The total length is: common prefix/suffix * 2 + palindrome starting after prefix in T
49 if (j < tLength) {
50 maxPalindromeLength = Math.max(maxPalindromeLength,
51 dp[i][j] * 2 + palindromeLengthsFromT[j]);
52 }
53 }
54 }
55 }
56
57 return maxPalindromeLength;
58 }
59
60 /**
61 * Expands around the given center to find palindromes and updates the maximum
62 * palindrome length starting at each position.
63 *
64 * @param charArray the character array to search in
65 * @param palindromeLengths array to store maximum palindrome lengths
66 * @param left starting left index of expansion
67 * @param right starting right index of expansion
68 */
69 private void expand(char[] charArray, int[] palindromeLengths, int left, int right) {
70 // Expand while characters match and indices are valid
71 while (left >= 0 && right < charArray.length && charArray[left] == charArray[right]) {
72 // Update the maximum palindrome length starting at position 'left'
73 palindromeLengths[left] = Math.max(palindromeLengths[left], right - left + 1);
74 --left;
75 ++right;
76 }
77 }
78
79 /**
80 * Calculates the maximum palindrome length starting at each position in the array.
81 *
82 * @param charArray the character array to analyze
83 * @return array where index i contains the length of longest palindrome starting at position i
84 */
85 private int[] calculatePalindromeLengths(char[] charArray) {
86 int length = charArray.length;
87 int[] palindromeLengths = new int[length];
88
89 // For each position, check for palindromes with both odd and even lengths
90 for (int i = 0; i < length; ++i) {
91 // Check for odd-length palindromes (single character center)
92 expand(charArray, palindromeLengths, i, i);
93 // Check for even-length palindromes (two character center)
94 expand(charArray, palindromeLengths, i, i + 1);
95 }
96
97 return palindromeLengths;
98 }
99}
100
1class Solution {
2public:
3 int longestPalindrome(string s, string t) {
4 int m = s.size(), n = t.size();
5
6 // Reverse string t to find common substrings between s and reverse of t
7 ranges::reverse(t);
8
9 // Calculate the longest palindrome starting at each position for both strings
10 vector<int> longestPalindromeFromS = calculateLongestPalindromeFrom(s);
11 vector<int> longestPalindromeFromT = calculateLongestPalindromeFrom(t);
12
13 // Initialize answer with the longest palindrome in either string alone
14 int maxLength = max(ranges::max(longestPalindromeFromS),
15 ranges::max(longestPalindromeFromT));
16
17 // dp[i][j] represents the length of longest common suffix between s[0..i-1] and t[0..j-1]
18 vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
19
20 // Build DP table to find longest common substrings
21 for (int i = 1; i <= m; ++i) {
22 for (int j = 1; j <= n; ++j) {
23 if (s[i - 1] == t[j - 1]) {
24 // Extend the common substring
25 dp[i][j] = dp[i - 1][j - 1] + 1;
26
27 // Try to form palindrome: common_substring + palindrome_from_s
28 // The common substring contributes twice (original + reversed)
29 if (i < m) {
30 maxLength = max(maxLength, dp[i][j] * 2 + longestPalindromeFromS[i]);
31 }
32
33 // Try to form palindrome: common_substring + palindrome_from_t
34 if (j < n) {
35 maxLength = max(maxLength, dp[i][j] * 2 + longestPalindromeFromT[j]);
36 }
37 }
38 }
39 }
40
41 return maxLength;
42 }
43
44private:
45 // Expand around center to find palindrome and update the longest palindrome starting at each position
46 void expandAroundCenter(const string& s, vector<int>& longestFrom, int left, int right) {
47 while (left >= 0 && right < s.size() && s[left] == s[right]) {
48 // Update the longest palindrome starting at position 'left'
49 longestFrom[left] = max(longestFrom[left], right - left + 1);
50 --left;
51 ++right;
52 }
53 }
54
55 // Calculate the longest palindrome starting at each position in the string
56 vector<int> calculateLongestPalindromeFrom(const string& s) {
57 int n = s.size();
58 vector<int> longestFrom(n, 0);
59
60 for (int i = 0; i < n; ++i) {
61 // Check for odd-length palindromes (single character center)
62 expandAroundCenter(s, longestFrom, i, i);
63 // Check for even-length palindromes (two character center)
64 expandAroundCenter(s, longestFrom, i, i + 1);
65 }
66
67 return longestFrom;
68 }
69};
70
1/**
2 * Finds the longest palindrome that can be formed by concatenating a prefix of string s
3 * with a suffix of string t (or vice versa), or just using a substring from either string.
4 */
5function longestPalindrome(s: string, t: string): number {
6 /**
7 * Expands around center to find palindromes and updates the maximum palindrome length
8 * starting at each position in the array.
9 * @param str - The string to search for palindromes
10 * @param maxLengths - Array storing max palindrome length starting at each index
11 * @param left - Left pointer for expansion
12 * @param right - Right pointer for expansion
13 */
14 function expandAroundCenter(
15 str: string,
16 maxLengths: number[],
17 left: number,
18 right: number
19 ): void {
20 // Expand while characters match and we're within bounds
21 while (left >= 0 && right < str.length && str[left] === str[right]) {
22 // Update max palindrome length starting at position 'left'
23 maxLengths[left] = Math.max(maxLengths[left], right - left + 1);
24 left--;
25 right++;
26 }
27 }
28
29 /**
30 * Calculates the maximum palindrome length starting at each position in the string.
31 * @param str - The input string
32 * @returns Array where each index contains the max palindrome length starting at that position
33 */
34 function calculatePalindromeLengths(str: string): number[] {
35 const length = str.length;
36 const maxPalindromeLengths: number[] = Array(length).fill(0);
37
38 for (let i = 0; i < length; i++) {
39 // Check for odd-length palindromes (single character center)
40 expandAroundCenter(str, maxPalindromeLengths, i, i);
41 // Check for even-length palindromes (two character center)
42 expandAroundCenter(str, maxPalindromeLengths, i, i + 1);
43 }
44
45 return maxPalindromeLengths;
46 }
47
48 const sLength = s.length;
49 const tLength = t.length;
50
51 // Reverse string t for suffix-prefix matching
52 const reversedT = t.split('').reverse().join('');
53
54 // Calculate max palindrome lengths for both strings
55 const palindromeLengthsS = calculatePalindromeLengths(s);
56 const palindromeLengthsT = calculatePalindromeLengths(reversedT);
57
58 // Initialize answer with the longest palindrome from either string alone
59 let maxPalindromeLength = Math.max(...palindromeLengthsS, ...palindromeLengthsT);
60
61 // DP table for longest common prefix between s and reversed t
62 // dp[i][j] represents the longest common substring ending at s[i-1] and reversedT[j-1]
63 const dp: number[][] = Array.from(
64 { length: sLength + 1 },
65 () => Array(tLength + 1).fill(0)
66 );
67
68 // Fill DP table to find matching prefixes and suffixes
69 for (let i = 1; i <= sLength; i++) {
70 for (let j = 1; j <= tLength; j++) {
71 if (s[i - 1] === reversedT[j - 1]) {
72 // Extend the common substring length
73 dp[i][j] = dp[i - 1][j - 1] + 1;
74
75 // Check palindrome formed by: prefix from s + suffix from t + remaining palindrome in s
76 if (i < sLength) {
77 maxPalindromeLength = Math.max(
78 maxPalindromeLength,
79 dp[i][j] * 2 + palindromeLengthsS[i]
80 );
81 }
82
83 // Check palindrome formed by: prefix from s + suffix from t + remaining palindrome in t
84 if (j < tLength) {
85 maxPalindromeLength = Math.max(
86 maxPalindromeLength,
87 dp[i][j] * 2 + palindromeLengthsT[j]
88 );
89 }
90 }
91 }
92 }
93
94 return maxPalindromeLength;
95}
96
Time and Space Complexity
The time complexity of this code is O(m² + n² + m × n)
, where m
is the length of string s
and n
is the length of string t
.
Breaking down the time complexity:
- The
calc
function is called twice - once for strings
and once for reversed stringt
- For
calc(s)
: The function iterates through each position in the string (O(m)
iterations), and for each position, callsexpand
twice. Theexpand
function can potentially check up toO(m)
characters in the worst case (expanding from center to edges). This givesO(m²)
for processing strings
- For
calc(t)
: Similarly, this takesO(n²)
for processing reversed stringt
- The nested loops for dynamic programming iterate
m × n
times, withO(1)
operations in each iteration, contributingO(m × n)
- Total:
O(m² + n² + m × n)
However, the reference answer states O(m × (m + n))
. This appears to be a simplification or different interpretation. If we consider that typically m
and n
are of similar magnitude, or if m ≥ n
, then O(m² + n² + m × n)
could be bounded by O(m × (m + n))
.
The space complexity is O(m × n)
, where:
- The 2D array
f
usesO((m + 1) × (n + 1)) = O(m × n)
space - Arrays
g1
andg2
useO(m)
andO(n)
space respectively - Total:
O(m × n + m + n) = O(m × n)
(sincem × n
dominates for non-trivial inputs)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Palindrome Extension Logic
Pitfall: A common mistake is incorrectly calculating the total palindrome length when combining matched sequences with remaining palindromes. Developers often forget that the matched portion contributes twice to the final length (once from s
and once from reversed t
).
Incorrect Implementation:
# Wrong: Only counting matched portion once
ans = max(ans, f[i][j] + g1[i]) # Missing multiplication by 2
Correct Implementation:
# Correct: Matched portion appears twice in the final palindrome
ans = max(ans, f[i][j] * 2 + (0 if i >= m else g1[i]))
2. Off-by-One Errors in DP Indexing
Pitfall: The DP table uses 1-indexed positions while the palindrome arrays use 0-indexed positions. This mismatch frequently causes index errors when accessing the palindrome length arrays.
Incorrect Implementation:
for i in range(1, m + 1):
for j in range(1, n + 1):
if s[i-1] == t_reversed[j-1]:
f[i][j] = f[i-1][j-1] + 1
# Wrong: Using 1-indexed i directly with 0-indexed g1
ans = max(ans, f[i][j] * 2 + g1[i]) # IndexError when i == m
Correct Implementation:
for i, char_s in enumerate(s, 1): # i is 1-indexed
for j, char_t in enumerate(t_reversed, 1): # j is 1-indexed
if char_s == char_t:
dp[i][j] = dp[i-1][j-1] + 1
# Correct: Check bounds and use proper index
if i < m: # Ensure i is valid index for g1 (0-indexed)
ans = max(ans, dp[i][j] * 2 + g1[i])
3. Forgetting to Consider Single-String Palindromes
Pitfall: Only focusing on concatenated palindromes and forgetting that the longest palindrome might come from just one string alone.
Incorrect Implementation:
ans = 0 # Wrong: Starting with 0 ignores single-string palindromes # ... DP logic ... return ans
Correct Implementation:
# Initialize with the longest palindrome from either string alone
ans = max(*g1, *g2)
# ... DP logic ...
return ans
4. Not Handling Edge Cases Properly
Pitfall: Failing to handle edge cases when one or both strings are empty, or when the matching sequence extends to the end of either string.
Solution: Always check boundaries before accessing array elements:
# Check if there are remaining characters before accessing palindrome arrays
if i < m:
ans = max(ans, dp[i][j] * 2 + palindrome_lengths_s[i])
else:
ans = max(ans, dp[i][j] * 2) # No remaining characters to add
if j < n:
ans = max(ans, dp[i][j] * 2 + palindrome_lengths_t_reversed[j])
else:
ans = max(ans, dp[i][j] * 2)
5. Misunderstanding the Problem Requirements
Pitfall: Thinking that the entire strings must be used, or that the substrings must be contiguous in a specific way.
Key Understanding:
- Substrings from
s
andt
can be empty - The concatenation order matters (substring from
s
first, then fromt
) - The goal is to form a palindrome, which requires the end of the
s
substring to match (in reverse) with the beginning of thet
substring
Implementation Tip: Reversing t
at the beginning simplifies the matching logic, as you're now looking for common prefixes between s
and reversed t
.
Consider the classic dynamic programming of longest increasing subsequence:
Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
For example, the length of LIS for [50, 3, 10, 7, 40, 80]
is 4
and LIS is
[3, 7, 40, 80]
.
What is the recurrence relation?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
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
Coding Interview 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
Want a Structured Path to Master System Design Too? Don’t Miss This!