Problem Description
Given a lowercase string s, find the length of the longest subsequence which is a palindrome with even length and satisfies an additional rule: aside from the very middle pair, every two consecutive characters in the subsequence must be different. In other words, the subsequence (which is “good”) must be a palindrome of even length, and if you look at every adjacent pair of characters it must be that they differ, except for the two characters in the center (which come from the same pair).
For example, if s = "bbabab", one answer is "baab" (length 4). Note that “bcb” is not acceptable because its length is odd, and “bbbb” is not acceptable because (apart from the middle pair) adjacent characters are equal.
Key Insights
- We want an even-length palindromic subsequence that is “good” – that is, its left half (when read normally) should have no adjacent equal letters; the right half will be its mirror (and its first character may equal the last character of the left half).
- We can think of constructing the palindrome in pairs: each pair contributes 2 characters. When choosing a new pair (with both characters equal), the left (first half) character must be different from the previous pair’s left character.
- A recursive formulation (DP) can be designed over an interval [l, r] of the original string with an extra parameter representing the last chosen left character (or a sentinel if none was chosen so far). For each character c (from ‘a’ to ‘z’) different from the previous left character, we want to check whether c appears at least twice in the current segment. If yes, we can “pair up” its leftmost and rightmost occurrences and add 2 plus the optimal answer from the “middle” segment, while updating the last chosen left character to c.
- To speed up these searches, precomputing for every character the ordered list of indices where it appears allows efficient queries (using binary search) for the first occurrence ≥ l and last occurrence ≤ r.
- Finally, the answer is given by dp(0, n – 1, sentinel) where sentinel indicates that no left character has yet been chosen.
Space and Time Complexity
Time Complexity: O(n² * 26 * log(n))
Space Complexity: O(n² * 27) for memoization plus O(n) for precomputed index lists
Solution
We use dynamic programming with recursion and memoization. The state is defined as dp(l, r, prev) where l and r denote the current substring boundaries and prev is the last chosen left-half character (or a special sentinel value such as -1 if none is chosen). For each character c from 'a' to 'z' (skipping if c equals prev) we check if there is at least one occurrence in s[l..r] and, crucially, if there is a pair (i, j) (with i < j) such that s[i] = s[j] = c. Using our precomputed lists for each character, we can quickly obtain the leftmost index and rightmost index of c in the interval. If such a pair exists then one candidate answer is 2 (for the pair) plus dp(i+1, j-1, c) where the new “prev” becomes c (ensuring that the next added pair’s left letter is different). We take the maximum candidate across all characters and memoize the result.
The extra twist of “no two consecutive characters equal, except for the two middle ones” is managed by the fact that if we add a new pair (with left character c), we only allow that when c is not equal to the previously chosen left character.