fn longest_palindrome(s: &str) -> String { let chars: Vec<char> = s.chars().collect(); let mut start = 0; let mut end = 0; for i in 0..chars.len() { let len1 = expand_around_center(&chars, i, i); let len2 = expand_around_center(&chars, i, i + 1); let len = len1.max(len2); if len > end - start { start = i.saturating_sub((len - 1) / 2); end = i + len / 2; } } chars[start..=end].iter().collect() } fn expand_around_center(chars: &[char], mut left: usize, mut right: usize) -> usize { while left <= right && right < chars.len() && chars[left] == chars[right] { if left == 0 { break; } left -= 1; right += 1; } right - left - 1 } fn main() { let input = "babad"; let result = longest_palindrome(input); println!("{}", result); }
The code expands around each character and between characters to find palindromes. For input "babad", both "bab" and "aba" are valid longest palindromes of length 3. However, the code picks the first longest palindrome it finds, which is "bab".
fn longest_palindrome(s: &str) -> String { let n = s.len(); if n == 0 { return String::new(); } let chars: Vec<char> = s.chars().collect(); let mut dp = vec![vec![false; n]; n]; let mut start = 0; let mut max_len = 1; for i in 0..n { dp[i][i] = true; } for length in 2..=n { for i in 0..=n - length { let j = i + length - 1; if chars[i] == chars[j] { if length == 2 || dp[i + 1][j - 1] { dp[i][j] = true; if length > max_len { start = i; max_len = length; } } } } } chars[start..start + max_len].iter().collect() } fn main() { let input = "cbbd"; let result = longest_palindrome(input); println!("{}", result); }
The dynamic programming table marks substrings that are palindromes. For input "cbbd", the longest palindrome substring is "bb".
fn manacher(s: &str) -> String { let t: Vec<char> = s.chars().flat_map(|c| vec!['#', c]).chain(std::iter::once('#')).collect(); let n = t.len(); let mut p = vec![0; n]; let mut center = 0; let mut right = 0; let mut max_len = 0; let mut max_center = 0; for i in 0..n { let mirror = 2 * center as isize - i as isize; if i < right { p[i] = p[mirror as usize].min(right - i); } while i + p[i] + 1 < n && i >= p[i] + 1 && t[i + p[i] + 1] == t[i - p[i] - 1] { p[i] += 1; } if i + p[i] > right { center = i; right = i + p[i]; } if p[i] > max_len { max_len = p[i]; max_center = i; } } let start = (max_center - max_len) / 2; s.chars().skip(start).take(max_len).collect() } fn main() { let input = "abacdfgdcaba"; let result = manacher(input); println!("{}", result); }
The while loop checks indices i + p[i] + 1 and i - p[i] - 1 without ensuring they are within bounds, causing an index out of bounds panic.
Expand around center checks each center and expands, resulting in O(n^2). Manacher's algorithm uses clever preprocessing to achieve O(n). Dynamic programming fills an n x n table, also O(n^2).
Suffix trees or suffix automatons can be adapted to track palindromic substrings efficiently in streaming data. Manacher's algorithm requires full string and is not online. Rolling hash with binary search is possible but less efficient. Storing all substrings is too slow.
