C++ Manacher 算法

17 Mar 2025 | 4 分钟阅读

引言

回文串,这种正读反读都一样的迷人序列,一直以来都吸引着数学家和计算机科学家的目光。在计算机科学中,高效地识别回文子串是一个常见的挑战。Manacher 算法是由计算机科学家 Glenn Manacher 开发的一项突破性技术,为这个问题提供了一个优雅的解决方案。

理解问题

给定一个字符串,任务是找到其中最长的回文子串。暴力解法可能需要检查所有可能的子串是否具有回文特性,但这种方法计算成本高昂,尤其对于长字符串而言。而 Manacher 算法则实现了线性时间复杂度,使其成为回文子串检测的强大工具。

Manacher 算法概述

Manacher 算法旨在找到给定字符串中最长的回文子串。与其他算法不同,Manacher 算法专门设计用于高效处理奇数和偶数长度的回文串。该算法利用了回文串的对称性来降低时间复杂度。

Manacher 算法背后的关键洞察是“中心”及其关联的“回文半径”的概念。中心是字符串中的一个位置,而回文半径是从该中心到以此为中心的回文串最外层字符的距离。Manacher 算法通过利用先前处理过的字符串部分的信息来避免重复计算。

Manacher 算法的工作原理

Manacher 算法结合了动态规划和巧妙的观察来找到最长的回文子串。其核心思想是维护已经处理过的子串的回文属性信息。

以下是 Manacher 算法的主要步骤

预处理字符串

  • 在字符串中的每对字符之间插入特殊字符(通常是 '#' 或 '$'),以处理奇数和偶数长度的回文串。
  • 这一步有助于统一处理奇数和偶数长度的回文串。

维护回文信息

  • 维护一个数组(通常称为 P)来存储有关子串回文属性的信息。
  • 用零初始化该数组。

寻找回文串

  • 遍历修改后字符串中的每个字符。
  • 对于每个字符,通过考虑对称性和先前计算的值来确定其回文长度。

寻找最长回文串

  • 在迭代过程中跟踪最大回文长度及其中心。
  • 使用此信息提取最长的回文子串。

实施

说明

  • 程序首先将输入字符串 s 转换为一个新字符串 T,方法是在原始字符串的每对字符之间插入 '#' 字符。
  • 程序初始化一些变量,例如 n(转换后字符串 T 的长度)、一个向量 P 用于存储以每个位置为中心的回文长度,以及两个变量 CR,分别表示当前已知回文的中心边界。
  • 程序遍历转换后字符串 T 中的每个字符。对于每个字符,它尝试扩展以该位置为中心的回文。它利用先前计算出的回文信息来优化计算。
  • 如果以当前位置为中心的回文扩展超出了边界 (R),程序会相应地更新中心 (C) 和右边界 (R)。这确保了算法通过利用回文的对称性来有效地跳过不必要的比较。
  • 在处理完转换后字符串中的所有字符后,程序在向量 P 中找到最大元素。
  • 它确定中心索引并计算最长回文子串的起始索引。

程序输出

Manacher's Algorithm in c++

为什么需要 Manacher 算法

寻找最长回文子串的暴力方法涉及检查每个可能的子串是否为回文。然而,这种方法的时间复杂度为 O(n^3),对于长字符串来说不切实际。

Manacher 算法通过利用回文的对称性对此进行了改进。它只处理字符串中的每个字符一次,从而实现了 O(n) 的线性时间复杂度。

结论

总之,C++ 中的 Manacher 算法是解决在给定字符串中寻找最长回文子串问题的强大而高效的方案。该算法能够实现线性时间复杂度,使其在性能至关重要的大规模应用中尤其具有吸引力。通过巧妙地利用回文串的特性,Manacher 算法消除了冗余计算,相比其他传统方法,提供了一个更快、更优化的解决方案。

此外,在 C++ 中实现 Manacher 算法展示了该语言在简洁表达复杂算法方面的优雅性和多功能性。代码的清晰度和可读性使其易于理解,方便开发人员根据需要进行理解和修改。另外,使用标准的 C++ 结构和库增强了该算法的可移植性,使其能方便地集成到各种软件项目中。