Finding the longest palindromic substring within a given string is a classic computer science problem with applications in various domains, from bioinformatics to natural language processing. This post will explore different approaches to solving this problem in Python, focusing on efficiency and readability.
Understanding the Problem
A palindrome is a sequence that reads the same backward as forward (e.g., “madam,” “racecar,” “level”). The goal is to identify the longest substring within a larger string that satisfies this palindromic property. For instance, in the string “bananas,” the longest palindromic substring is “anana.”
Approach 1: Brute Force
The most straightforward approach involves checking every possible substring for palindromic properties. While simple to understand, this method is computationally expensive, with a time complexity of O(n³), where n is the length of the string.
def longest_palindrome_brute_force(s):
= len(s)
n = ""
longest_palindrome for i in range(n):
for j in range(i, n):
= s[i:j+1]
substring if substring == substring[::-1] and len(substring) > len(longest_palindrome):
= substring
longest_palindrome return longest_palindrome
= "bananas"
string = longest_palindrome_brute_force(string)
result print(f"The longest palindromic substring of '{string}' is: {result}") #Output: anana
This code iterates through all possible substrings and compares each to its reverse. While functional, it’s inefficient for larger strings.
Approach 2: Dynamic Programming
Dynamic programming offers a significant performance improvement. It builds a table to store whether substrings are palindromes, avoiding redundant calculations. This approach achieves a time complexity of O(n²).
def longest_palindrome_dp(s):
= len(s)
n if n < 2:
return s
= [[False] * n for _ in range(n)]
dp = 0
start = 1
max_len for i in range(n):
= True # Single characters are palindromes
dp[i][i] for i in range(n - 1):
if s[i] == s[i + 1]:
+ 1] = True
dp[i][i = i
start = 2
max_len for k in range(3, n + 1):
for i in range(n - k + 1):
= i + k - 1
j if s[i] == s[j] and dp[i + 1][j - 1]:
= True
dp[i][j] if k > max_len:
= i
start = k
max_len return s[start:start + max_len]
#Example Usage
= "babad"
string = longest_palindrome_dp(string)
result print(f"The longest palindromic substring of '{string}' is: {result}") # Output: bab or aba (both are correct)
This dynamic programming solution is considerably more efficient than the brute-force approach, especially for longer input strings.
Approach 3: Expand Around Center
This approach cleverly expands outwards from the center of potential palindromes. It considers both odd-length and even-length palindromes, further optimizing the search. The time complexity remains O(n²), but it generally performs faster than the dynamic programming approach in practice due to reduced overhead.
def longest_palindrome_expand_around_center(s):
= len(s)
n if n < 2:
return s
= 0
start = 1
max_len for i in range(n):
# Odd length palindromes
= i, i
l, r while l >= 0 and r < n and s[l] == s[r]:
if r - l + 1 > max_len:
= r - l + 1
max_len = l
start -= 1
l += 1
r # Even length palindromes
= i, i + 1
l, r while l >= 0 and r < n and s[l] == s[r]:
if r - l + 1 > max_len:
= r - l + 1
max_len = l
start -= 1
l += 1
r return s[start:start + max_len]
= "cbbd"
string = longest_palindrome_expand_around_center(string)
result print(f"The longest palindromic substring of '{string}' is: {result}") # Output: bb
This method iterates through each character as a potential center, expanding outwards to find the longest palindrome centered at that point. It elegantly handles both odd and even length palindromes.