【算法】manacher

1. 算法简介#

Manacher 算法,俗称马拉车。是一个可以在线性时间复杂度内高效解决最大回文子串的问题。

2. 算法流程#

暴力想必大家也都会,就是枚举中心点然后暴力扩展长度。时间复杂度 O(n2)

还有就是字符串哈希 + 二分:枚举中心点,将暴力的扩展变成二分。因为长度越长更不能回文,长度越短更能回文,满足单调性。判断子串相同就用哈希即可。这样可以做到时间复杂度 O(nlogn)

最后是 manacher 算法,就是利用那些已经计算过的信息看来推导没有计算过的信息。

首先处理一下奇回文和偶回文的情况:在字符串的开头、结尾以及每一个字符之间插入一个没有在串中出现过的字符 &$#,可以发现这样处理过后的字符串的最大回文串的开头结尾均为 "插入字符",原最大回文串长为新串的最大回文半径长度 1

对于每一个位置 i 维护一个最长回文半径 di,并维护一个全局最长回文半径 R 以及她所在的中心位置 M,然后分类讨论。

  • i>r,显然无法利用原有的信息,直接暴力去做。
  • ir,找到 i 在全局最长回文串下对应的 k=2Mi 位置,可以分为两类;
    • 如果 dk 对应的区间被包含于 [2MR,R] 区间中,则 dk=di
    • 如果 dk 对应的区间没有被包含于 [2MR,R] 区间中,则令 dk=Ri+1 然后暴力匹配;

根据下图加深理解:

  1. 如果 dk 对应的区间被包含于 [2MR,R] 区间中,则 dk=di

image

  1. 如果 dk 对应的区间没有被包含于 [2MR,R] 区间中,则令 dk=Ri+1 然后暴力匹配;

image

3. 算法实现#

#include<bits/stdc++.h>
#define int long long
#define reg register 
#define For(i,l,r) for(reg int i=l;i<=r;++i)
#define FOR(i,r,l) for(reg int i=r;i>=l;--i)

using namespace std;

const int N = 5e7; 

int n, d[N];

char s[N];

string t = " ";

int Manacher() {
  int ans = 0;
  for (reg int i = 1, M = 0, r = 0; i <= n; ++i) {
    if(i <= r) d[i] = min(d[2 * M - i], r - i + 1);
    while(i - d[i] >= 1 && i + d[i] <= n && t[i - d[i]] == t[i + d[i]]) d[i]++;
    if(i + d[i] - 1 > r) M = i, r = i + d[i] - 1;
    ans = max(ans, d[i] - 1);
  }
  return ans;
}

signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> (s + 1);
  n = strlen(s + 1);
  t += '#';
  For(i,1,n) {
    t += s[i], t += "#";
  }
  n = 2 * n + 1;
  cout << Manacher() << '\n';
  return 0;
}

后记#

可以拿 Z 函数和 Manacher 的关键代码进行对比:

Manacher:

for (reg int i = 1, M = 0, r = 0; i <= n; ++i) {
  if(i <= r) d[i] = min(d[2 * M - i], r - i + 1);
  while(i - d[i] >= 1 && i + d[i] <= n && t[i - d[i]] == t[i + d[i]]) d[i]++;
  if(i + d[i] - 1 > r) M = i, r = i + d[i] - 1;
}

Z 函数:

for (reg int i = 2, l, r = 0; i <= m; ++i) {
  if(i <= r) z[i] = min(z[i - l + 1], r - i + 1);
  while(i + z[i] <= m && t[1 + z[i]] == t[i + z[i]]) z[i]++;
  if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
}

这俩玩意的代码简直一模一样,相似度 85%,所以她们俩也很好背。

作者:Daniel-yao

出处:https://www.cnblogs.com/Daniel-yao/p/18554828

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Daniel_yzy  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示