热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Manacher算法详解

本文详细介绍了Manacher算法,该算法能够在O(n)时间内找到字符串中的最长回文子串。通过对字符串进行预处理,并使用动态规划的思想,Manacher算法能够高效地解决这一问题。

Manacher算法是一种高效的算法,用于在O(n)时间内找到字符串中的最长回文子串。本文将详细介绍该算法的原理和实现步骤。

### 算法原理

Manacher算法的核心思想是对字符串进行预处理,使其所有的回文子串都具有奇数长度,从而简化后续的处理过程。

#### 预处理步骤

(1) 在每个字符之间插入一个特殊的分隔符(例如#),这样可以将所有可能的奇数或偶数长度的回文子串转换为奇数长度的回文子串。例如,字符串“abba”变为“#a#b#b#a#”,字符串“aba”变为“#a#b#a#”。这样做可以统一处理不同长度的回文子串。

(2) 为了简化边界处理,可以在字符串的开头添加一个特殊的字符(例如$),这样可以避免在处理过程中出现越界的情况。例如,字符串“$#a#b#a#”。

#### 动态规划数组P[i]

定义一个数组P[i],用于记录以字符S[i]为中心的最长回文子串的半径(包括S[i])。例如,对于字符串“12212321”,经过预处理后变为S[] = “$#1#2#2#1#2#3#2#1#”,对应的P数组为:

S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #
P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1

可以看出,P[i]-1正好是原字符串中回文子串的总长度。

### 计算P[i]的步骤

算法引入了两个辅助变量id和mx,其中id表示当前已知的最大回文子串的中心位置,mx表示该回文子串的右边界(即id + P[id])。

#### 处理过程

(1) 如果当前处理的字符i在mx的范围内(即mx > i),则可以利用之前的结果来加速计算。具体来说,设j = 2 * id - i,即j是i关于id的对称点。此时,P[i]的值可以通过以下方式确定:

  • 如果mx - i > P[j],则P[i] = P[j]。
  • 如果mx - i <= P[j],则P[i] = mx - i,但需要进一步匹配以确定最终的P[i]。

(2) 如果当前处理的字符i不在mx的范围内(即mx <= i),则需要从头开始逐个匹配,初始化P[i] = 1,然后逐步扩展回文子串的范围。

### 代码实现

[cpp] view plain copy
  1. #include
  2. #include
  3. using namespace std;
  4. char* InitStr(char* pStr) {
  5. assert(pStr != NULL);
  6. int nCount = 0;
  7. int nLenOldStr = strlen(pStr);
  8. int nLenNewStr = (nLenOldStr <<1) + 3; // ab -> $#a#b#0
  9. char* pNewStr = new char[nLenNewStr];
  10. pNewStr[nCount++] = '$';
  11. for (int i = 0; i
  12. pNewStr[nCount++] = '#';
  13. pNewStr[nCount++] = pStr[i];
  14. }
  15. pNewStr[nCount++] = '#';
  16. pNewStr[nCount] = '\0';
  17. return pNewStr;
  18. }
  19. int Manacher(char* pStr) {
  20. assert(pStr != NULL);
  21. int nId = 1;
  22. int nMx = 0;
  23. int nLOngest= 0;
  24. char* pNewStr = InitStr(pStr);
  25. int nLenStr = strlen(pNewStr);
  26. int* p = new int[nLenStr];
  27. memset(p, 0, sizeof(int) * nLenStr);
  28. for (int i = 1; pNewStr[i] != '\0'; i++) {
  29. if (nMx > i) {
  30. p[i] = min(p[(nId <<1) - i], nMx - i);
  31. } else {
  32. p[i] = 1; // 回文子串长度等于本身
  33. }
  34. while (pNewStr[i + p[i]] == pNewStr[i - p[i]]) {
  35. p[i]++;
  36. }
  37. if (i + p[i] > nMx) {
  38. nMx = i + p[i];
  39. nId = i;
  40. }
  41. if (pNewStr[i] != '#') {
  42. nLOngest= max(nLongest, p[i]);
  43. }
  44. }
  45. delete[] pNewStr;
  46. delete[] p;
  47. return nLongest - 1;
  48. }
  49. int main() {
  50. char strArr[] = "12212221";
  51. cout <
  52. system("pause");
  53. return 0;
  54. }

通过上述步骤,Manacher算法能够在O(n)时间内找到字符串中的最长回文子串,适用于各种实际应用场景。


推荐阅读
  • 使用GDI的一些AIP函数我们可以轻易的绘制出简 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本题探讨了一种字符串变换方法,旨在判断两个给定的字符串是否可以通过特定的字母替换和位置交换操作相互转换。核心在于找到这些变换中的不变量,从而确定转换的可能性。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 文件描述符、文件句柄与打开文件之间的关联解析
    本文详细探讨了文件描述符、文件句柄和打开文件之间的关系,通过具体示例解释了它们在操作系统中的作用及其相互影响。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 探索1000以内的完美数:因数和等于自身
    本文探讨了如何在1000以内找到所有完美数,即一个数的因数(不包括自身)之和等于该数本身。例如,6是一个完美数,因为1 + 2 + 3 = 6。通过编程实现这一过程,可以更好地理解完美数的特性。 ... [详细]
author-avatar
elgin2010
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有