Solving Longest Palindromic Substring: A Multi-Language Approach
The Longest Palindromic Substring problem is a classic algorithmic challenge that tests your understanding of string manipulation and dynamic programming. Let's solve it in multiple programming languages and explore different approaches.
Problem Statement
Given a string s
, return the longest palindromic substring in s
.
Example 1:
1Input: s = "babad"2Output: "bab"3Explanation: "aba" is also a valid answer.
Example 2:
1Input: s = "cbbd"2Output: "bb"
Understanding the Problem
A palindrome is a string that reads the same forward and backward. The challenge is to find the longest such substring within a given string. There are several approaches to solve this:
- Brute Force (O(n³))
- Dynamic Programming (O(n²))
- Expand Around Center (O(n²))
- Manacher's Algorithm (O(n)) - advanced
We'll implement the "Expand Around Center" approach as it's both efficient and intuitive.
TypeScript Implementation
1function longestPalindrome(s: string): string {2 if (s.length < 2) return s;34 let start = 0;5 let maxLength = 1;67 function expandAroundCenter(left: number, right: number): void {8 while (left >= 0 && right < s.length && s[left] === s[right]) {9 const currentLength = right - left + 1;10 if (currentLength > maxLength) {11 start = left;12 maxLength = currentLength;13 }14 left--;15 right++;16 }17 }1819 for (let i = 0; i < s.length; i++) {20 expandAroundCenter(i, i); // Odd length palindromes21 expandAroundCenter(i, i + 1); // Even length palindromes22 }2324 return s.substring(start, start + maxLength);25}2627// Example usage28console.log(longestPalindrome("babad")); // "bab"29console.log(longestPalindrome("cbbd")); // "bb"
Ruby Implementation
1def longest_palindrome(s)2 return s if s.length < 234 start = 05 max_length = 167 def expand_around_center(s, left, right, start, max_length)8 while left >= 0 && right < s.length && s[left] == s[right]9 current_length = right - left + 110 if current_length > max_length11 start[0] = left12 max_length[0] = current_length13 end14 left -= 115 right += 116 end17 end1819 start_ref = [start]20 max_length_ref = [max_length]2122 (0...s.length).each do |i|23 expand_around_center(s, i, i, start_ref, max_length_ref) # Odd length24 expand_around_center(s, i, i + 1, start_ref, max_length_ref) # Even length25 end2627 s[start_ref[0], max_length_ref[0]]28end2930# Example usage31puts longest_palindrome("babad") # "bab"32puts longest_palindrome("cbbd") # "bb"
Python Implementation
1def longest_palindrome(s: str) -> str:2 if len(s) < 2:3 return s45 start = 06 max_length = 178 def expand_around_center(left: int, right: int) -> None:9 nonlocal start, max_length1011 while left >= 0 and right < len(s) and s[left] == s[right]:12 current_length = right - left + 113 if current_length > max_length:14 start = left15 max_length = current_length16 left -= 117 right += 11819 for i in range(len(s)):20 expand_around_center(i, i) # Odd length palindromes21 expand_around_center(i, i + 1) # Even length palindromes2223 return s[start:start + max_length]2425# Example usage26print(longest_palindrome("babad")) # "bab"27print(longest_palindrome("cbbd")) # "bb"
Code Walkthrough
Let's break down the key components of our solution:
-
Base Case
- If string length is less than 2, return the string itself
- A single character is always a palindrome
-
Expand Around Center Function
- Takes left and right pointers as parameters
- Expands outward while characters match
- Updates global tracking of longest palindrome found
-
Main Loop
- Iterates through each character
- Checks for both odd and even length palindromes
- Uses two separate expansions for each position
-
Time and Space Complexity
- Time Complexity: O(n²)
- Space Complexity: O(1)
Performance Optimization Tips
-
Early Termination
- If remaining string length is less than current max, stop searching
- Implement bounds checking before expansion
-
Memory Management
- TypeScript/JavaScript: Use substring instead of slice
- Python: Use string slicing efficiently
- Ruby: Use proper string range operations
-
Language-Specific Optimizations
- TypeScript: Use type annotations for better performance
- Python: Consider using memoryview for large strings
- Ruby: Use frozen string literals when possible
Related Problems
- Palindromic Substrings (LeetCode 647)
- Valid Palindrome (LeetCode 125)
- Palindrome Pairs (LeetCode 336)
Related Resources
- Dynamic Programming - Wikipedia article on dynamic programming concepts
- String (computer science) - Wikipedia article on string data structures
- Palindrome - Wikipedia article on palindromes
- Time complexity - Wikipedia article on algorithmic time complexity
Conclusion
The Longest Palindromic Substring problem demonstrates the importance of efficient algorithm design and language-specific implementations. While the core logic remains similar across languages, each implementation takes advantage of language-specific features for optimal performance.
Remember to practice this problem with different input sizes and edge cases to fully understand its complexity and optimization opportunities.