pub fn shortest_palindrome(s: &str) -> String {
if s.is_empty() {
return "".to_string();
}
let p_chars: Vec<char> = s.chars().collect();
let suffix = raw_suffix_function(&p_chars);
let mut s_chars: Vec<char> = s.chars().rev().collect();
let dp = invert_suffix_function(&p_chars, &s_chars, &suffix);
s_chars.append(&mut p_chars[dp[p_chars.len() - 1]..p_chars.len()].to_vec());
s_chars.iter().collect()
}
pub fn raw_suffix_function(p_chars: &[char]) -> Vec<usize> {
let mut suffix = vec![0; p_chars.len()];
for i in 1..p_chars.len() {
let mut j = suffix[i - 1];
while j > 0 && p_chars[j] != p_chars[i] {
j = suffix[j - 1];
}
suffix[i] = j + if p_chars[j] == p_chars[i] { 1 } else { 0 };
}
suffix
}
pub fn invert_suffix_function(p_chars: &[char], s_chars: &[char], suffix: &[usize]) -> Vec<usize> {
let mut dp = vec![0; p_chars.len()];
dp[0] = if p_chars[0] == s_chars[0] { 1 } else { 0 };
for i in 1..p_chars.len() {
let mut j = dp[i - 1];
while j > 0 && s_chars[i] != p_chars[j] {
j = suffix[j - 1];
}
dp[i] = j + if s_chars[i] == p_chars[j] { 1 } else { 0 };
}
dp
}
#[cfg(test)]
mod tests {
use crate::string::shortest_palindrome;
macro_rules! test_shortest_palindrome {
($($name:ident: $inputs:expr,)*) => {
$(
#[test]
fn $name() {
use crate::string::is_palindrome;
let (s, expected) = $inputs;
assert!(is_palindrome(expected));
assert_eq!(shortest_palindrome(s), expected);
assert_eq!(shortest_palindrome(expected), expected);
}
)*
}
}
test_shortest_palindrome! {
empty: ("", ""),
extend_left_1: ("aacecaaa", "aaacecaaa"),
extend_left_2: ("abcd", "dcbabcd"),
unicode_1: ("അ", "അ"),
unicode_2: ("a牛", "牛a牛"),
}
}