Algo: Manacher's Algorithm for Palindromes
AI-Generated Content
Algo: Manacher's Algorithm for Palindromes
Finding the longest palindromic substring is a classic problem that seems deceptively simple. A naive check of every possible substring would take time, and even an improved center-expansion approach runs in . Manacher's algorithm solves this optimally by finding all maximal palindromes centered at each position in a string in linear time. Its power lies in a clever transformation and an ingenious exploitation of palindrome symmetry to avoid redundant computations, making it a cornerstone technique for competitive programming and text analysis.
Transforming the Problem: Handling Even and Odd Lengths
The first challenge in any palindrome algorithm is handling substrings of both even and odd lengths uniformly. A center-expansion approach for an odd-length palindrome, like "racecar", expands from a single character. For an even-length palindrome like "abba", you must expand from the space between characters. This complicates logic and implementation.
Manacher's algorithm solves this by inserting a dummy character (commonly '#') between every character in the original string and at the ends. For example, the string "abba" transforms into "^#a#b#b#a#" (where '^' and '' are sentinels to prevent boundary checks). This transformation guarantees that every palindrome in the new string is odd-length, centered on an actual character or a '#'. The center of the original even palindrome "abba" becomes the '#' between the two 'b's. After processing, we can easily convert radii back to the original string's indices.
Leveraging Symmetry: The Core Insight
The heart of Manacher's algorithm is its use of previously computed information to accelerate new computations. The algorithm maintains an array P (or radius), where P[i] stores the radius (half-length) of the palindrome centered at position i in the transformed string. It also tracks C, the center of the current rightmost palindrome, and R, its right boundary.
When processing a new center i, we use the symmetric property of palindromes around C. The mirror of i is mirror = 2*C - i. Because the palindrome centered at C spans from C-R to R, we know that the palindrome at mirror is at least contained within this large palindrome. Therefore, we can initialize:
P[i] = min(R - i, P[mirror]).
This is the critical optimization. Instead of starting expansion from a radius of 0, we can jump-start P[i] with this minimum value. We only need to perform character comparisons for expansion beyond this guaranteed radius. This reuse of information is what transforms the algorithm from to , as each character is successfully compared at most a constant number of times—once when it's inside R (via the min operation) and potentially once more when it expands R itself.
The Algorithm Step-by-Step
Let's walk through the algorithm's flow with the transformed string S.
- Initialize: Create array
Pof lengthn(length of transformed string) filled with zeros. Set centerC = 0and right boundaryR = 0. - Loop through each index
ifrom1ton-2. - Get Mirror & Jump-start: Calculate
mirror = 2*C - i. SetP[i] = (R > i) ? min(R - i, P[mirror]) : 0.
- If
iis within the current right boundaryR, we use the symmetric property. - If
iis outsideR, we initializeP[i]to 0.
- Expand: While the characters at
S[i + 1 + P[i]]andS[i - 1 - P[i]]are equal, incrementP[i]. This attempts to expand the palindrome centered ati. - Update Center and Boundary: If the palindrome centered at
iexpands pastR, updateC = iandR = i + P[i]. This means we have found a new, farther-reaching palindrome to use as our symmetry reference. - Extract Original Indices: After building
P, the longest palindrome in the original string corresponds to the maximum value inP. The center indexiand radiusP[i]in the transformed string can be converted back. The original length isP[i](the radius in the transformed string). The original start index is(i - P[i]) / 2.
This process ensures every character is used as a center, and the expansion step is amortized constant time due to the constant forward movement of R.
Application: Longest Palindromic Substring
Manacher's algorithm is the definitive solution for the Longest Palindromic Substring problem. By finding max(P[i]) and its corresponding center i, you have directly located the answer. The algorithm provides much more—it gives you the lengths of all maximal palindromes centered at every position in linear time. This comprehensive data is useful for more complex problems, such as counting all palindromic substrings or finding palindromic structures in DNA sequences.
The transformed string technique ensures you find both even and odd candidates. For example, if the maximum P[i] is centered on a '#', the original palindrome is even-length. If centered on an original character, it's odd-length. The conversion formula handles this seamlessly.
Common Pitfalls
- Incorrect Transformation or Index Conversion: A frequent error is mishandling the sentinel characters or the index math when converting between the transformed and original string. Always use a consistent transformation pattern (e.g.,
"^#" + s.split('').join('#') + "#$") and derive the conversion formulas carefully. Test with simple even and odd cases like "a" and "aa". - Forgetting to Update C and R: The algorithm's efficiency depends on maintaining the rightmost palindrome (
CandR). A common mistake is to updateCtoievery time, instead of only wheni + P[i] > R. Updating only when the boundary expands is crucial for correctness and performance. - Off-by-One Errors in the Expansion Loop: The expansion condition
S[i + 1 + P[i]] == S[i - 1 - P[i]]must match your transformed string's indices. Using<=or incorrect offsets will lead to infinite loops or incorrect radii. Remember thatP[i]is the current known radius, and you are checking the next character beyond it. - Misunderstanding the
min(R - i, P[mirror])Assignment: This line is the optimization. UsingP[mirror]directly wheniis withinRis safe because of symmetry. UsingR - iis necessary because the palindrome atmirrormay extend beyond the left boundary of the large palindrome centered atC; its symmetry cannot be guaranteed outsideR. Taking the minimum ensures we only use the part we know is identical.
Summary
- Manacher's algorithm finds all maximal palindromic substrings in linear time by exploiting palindrome symmetry to avoid redundant character comparisons.
- The transformed string technique (inserting '#' between characters) handles both even- and odd-length palindromes uniformly by converting them all into odd-length palindromes in the new string.
- The algorithm maintains a radius array
Pand a reference palindrome defined by its centerCand right boundaryR. For a new centeri, it jump-startsP[i]using the minimum of(R - i)and the radius ofi's mirror, then expands only as needed. - It is the optimal solution for the longest palindromic substring problem and provides a complete palindrome-length map for the entire string.
- Careful implementation is required to correctly manage the transformed string indices, update the reference palindrome only when its boundary expands, and avoid off-by-one errors during expansion.