热门标签 | 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)时间内找到字符串中的最长回文子串,适用于各种实际应用场景。


推荐阅读
  • 本文介绍如何在Ubuntu环境下为OpenWrt系统构建并安装首个'Hello World'应用程序的IPK包。文章不仅涵盖了基本的环境搭建,还详细说明了代码编写、Makefile配置及最终的IPK包生成与安装过程。 ... [详细]
  • http:acm.hdu.edu.cnshowproblem.php?pid1846好几天没出题了,今天终于水了一题巴什博弈题。总结:【一】巴什博弈对象:一堆石子(可延伸 ... [详细]
  • 本文详细探讨了C++中赋值运算符重载函数(operator=)的使用方法和注意事项,结合实例分析了其参数、返回值、调用时机等关键点,并讨论了浅拷贝和深拷贝的区别及其重要性。 ... [详细]
  • 辗转相减法在求解最大等比值问题中的应用
    本文探讨了如何利用辗转相减法解决X星球大奖赛中奖金分配的数学问题,通过分析给定的数据点,计算出可能的最大等比值。 ... [详细]
  • 力扣93:复原IP地址问题解析(Golang实现)
    本文探讨了力扣平台上的第93号问题——复原IP地址。该问题要求从给定的纯数字字符串中,通过添加分隔符‘.’来构建所有可能的有效IP地址。有效IP地址由四个介于0至255之间的整数组成,不允许出现前导零。 ... [详细]
  • 本文探讨了在JavaScript中执行字符串形式代码的多种方法,包括使用eval()函数以及跨页面调用的方法。同时,文章详细介绍了JavaScript中字符串的各种常用方法及其应用场景。 ... [详细]
  • 在该问题中,若存在一个节点x满足特定条件,则x所在的强连通分量(SCC)同样满足条件。合法的SCC数量最多为1,因为多个SCC之间具有传递性,理论上应能合并。本文将通过拓扑排序和缩点技术来探讨这一算法的实现。 ... [详细]
  • 精通C++并非易事,为何它比其他语言更难掌握?这主要归因于C++的设计理念,即不强迫用户接受特定的编程风格或限制创新思维。本文探讨了如何有效学习C++,并介绍了几本权威的学习资源。 ... [详细]
  • 本文介绍如何在指定的Module中通过配置build.gradle文件来生成自定义名称和路径的JAR文件,适用于Gradle 2.4及以上版本的Android Studio环境。 ... [详细]
  • 深入理解设计模式之观察者模式
    本文详细介绍了观察者模式,这是一种行为设计模式,适用于当对象状态发生变化时,需要通知其他相关对象的场景。文中不仅解释了观察者模式的基本概念,还通过Java代码示例展示了其实现方法。 ... [详细]
  • 本文探讨了Java编程中MVC模式的优势与局限,以及如何利用Java开发一款基于鸟瞰视角的赛车游戏。 ... [详细]
  • 近期探讨了‘内部螺旋矩阵算法’的实现细节,并深入分析了面向对象编程中的可扩展性问题。基于这些讨论,本文通过引入桥梁设计模式对原有代码进行了优化与重构,以增强代码的灵活性和可维护性。 ... [详细]
  • 本文探讨了在使用MySQL数据库时遇到的一些基本问题,如连接失败和语句执行错误,并提供了多个有效的解决方案。 ... [详细]
  • 本文详细介绍了Oracle数据库中审计日志(audit trail)的配置方法及各参数选项的功能,包括如何启用系统范围的审计记录,以及如何将审计数据存储在不同的位置和格式。 ... [详细]
  • 本文基于《Linux命令行与Shell脚本编程大全》第三版的第十一章内容,探讨了如何构建基本的Shell脚本,包括命令组合、脚本创建、消息显示、变量使用、输入输出重定向、管道、数学运算及脚本退出等方面的知识。 ... [详细]
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社区 版权所有