马拉车算法【Manachar】

马拉车算法【Manachar】
[优秀的算法总结](https://blog.csdn.net/dyx404514/article/details/42061017?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162657705716780274134211%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162657705716780274134211&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-42061017.first_rank_v2_pc_rank_v29&utm_term=manacher%E7%AE%97%E6%B3%95&spm=1018.2226.3001.4187)
Manachar算法:

> 因为上面这一片博客已经将Manachar讲的很清楚了,我就不再多做赘述,直接说下算法流程以及结论。
>
> 1.预处理:将字符串间隔插入一个不会在原串出现的字符,可以给开始字符记为$结尾字符记为^
>
> 2. 变量所携带的信息
>
> 1. p[i]表示以当前字符i开始,最长的回文子串的半径是多少。注意,P[i]所拥有的回文串都是奇数串。
> 2. mx表示回文串最远可以到达那里,
> 3. resLen,表示P[i]的最大值,也就是我们需要求的最长回文子串的长度,注意,p[i]所表示的值,总是会比我们真实的原串的回文子串的长度多1。
> 4. resCentre表示最长回文子串的中间位置,对应原串位置为整除2,不用考虑是否下取整,因为原串的每个字符在对应的扩展后的串中,都是在偶数下标下的。
>
> 3. `p[i] = mx > i ? min(p[id * 2 - i], mx - i) : 1`
>
> p[i]没扩展的时候,只能在mx内取
>
> while(b[i - p[i]] == b[i + p[i]]) p[i] ++;
>
> 扩展当前i的p数组
>
> 更新mx:只要当前p更新了,一定mx也更新了,毕竟mx是我们的边界
>
> 4. 然后返回所需信息

模板:string写的,在字符长度大的情况下,可能会超时,建议,写成char形式。在下面也有
```cpp
#include <bits/stdc++.h>

using namespace std;

string Mannacher(string s)
{
//插入“#”
string t = "%#";
for (int i = 0; i < s.size(); i ++ )
{
t += s[i];
t += '#';
}

vector<int> p(t.size(), 0);
//mx表示某个回文串延展在最右端半径下标,id表示这个回文子串最中间位置下标
//resLen表示在对应C中最大回文子串的半径,resCentre表示最大回文串的中间位置
int mx = 0, id = 0, resLen = 0, resCentre = 0;

//建立p数组
for (int i = 1; i < t.size(); i ++ )
{
p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;

//遇到阿森纳中特殊情况,需要利用中心扩展法
while (t[i + p[i]] == t[i - p[i]]) p[i] ++;

//半径下标i + p[i]超过边界mx,需要更新
if (mx < i + p[i])
{
mx = i + p[i];
id = i;
}

//更新最大回文子串的信息,半径及中心位置
if (resLen < p[i])
{
resLen = p[i];
resCentre = i;
}
}

return s.substr((resCentre - resLen) / 2, resLen - 1);
}

int main()
{
string s;
while (cin >> s)
{
cout << Mannacher(s).size() << endl;
}

return 0;
}

```
题目:

[AcWing 3188. manacher算法]([3188. manacher算法 - AcWing题库](https://www.acwing.com/problem/content/3190/))

```cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 20000005;
char a[N], b[N];
int p[N];
int n;
void init()
{
n = strlen(a);
int k = 0;
b[k ++ ] = '$', b[k ++ ] = '#';
for (int i = 0; i < n; i ++ ) b[k ++ ] = a[i], b[k ++ ] = '#';
b[k ++ ] = '^';
n = k;
cout << b << endl;
}
int Manachar()
{
int mx = 0, id = 0, resLen = 0, resCentre = 0;
for (int i = 1; i < n; i ++ )
{
p[i] = mx > i ? min(p[id * 2 - i], mx - i) : 1;
while (b[i - p[i]] == b[i + p[i]]) p[i] ++;
if (mx < i + p[i])
{
mx = i + p[i];
id = i;
}
if (resLen < p[i])
{
resLen = p[i];
resCentre = i;
}
}
return resLen - 1;
}
int main()
{
cin >> a;
init();
cout << Manachar() << endl;
return 0;
}
```

 

posted @ 2021-07-18 16:36  rookie161  阅读(75)  评论(0编辑  收藏  举报