【算法日记】马拉车
作者:互联网
Manacher马拉车算法
马拉车是时间复杂度为O(N)来求最长回文子串算法。
神奇的事情:我从来没学过马拉车
刷USACO题单刷到了马拉车
马拉车第一步
在字符中间加入未在字符串中出现的间隔符
如 abba
变 #a#b#b#a3
这样无论字符串是奇串还是偶串,都可转为奇串的形式。
对于数组 p[i],表示以t[i]字符为中心的回文子串的半径,若p[i] = 1,则该回文子串就是t[i]本身
两个辅助变量mx和id,其中id为最大回文子串中心的位置,mx是回文串能延伸到的最右端的位置
如果mx > i, 则 p[i] = min(p[2 * id - i], mx - i)
否则, p[i] = 1
当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有 P[i] = P[j]
当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,就只能老老实实去匹配了。
马拉车模板
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
char s[1000];
char s_new[2000];
int p[2000];
int Init()
{
int len = strlen(s);
s_new[0] = '$';
s_new[1] = '#';
int j = 2;
for (int i = 0; i < len; i++)
{
s_new[j++] = s[i];
s_new[j++] = '#';
}
s_new[j] = '\0';
}
int Manacher()
{
int len = Init(); //取得新字符串长度并完成向s_new的转换
int maxLen = -1; //最长回文长度
int id;
int mx = 0;
for (int i = 1; i < len; i++)
{
if (i < mx)
p[i] = min(p[2 * id - i], mx - i); //需搞清楚上面那张图含义, mx和2*id-i的含义
else
p[i] = 1;
while (s_new[i - p[i]] == s_new[i + p[i]]) //不需边界判断,因为左有'$',右有'\0'
p[i]++;
//我们每走一步i,都要和mx比较,我们希望mx尽可能的远,这样才能更有机会执行if (i < mx)这句代码,从而提高效率
if (mx < i + p[i])
{
id = i;
mx = i + p[i];
}
maxLen = max(maxLen, p[i] - 1);
}
return maxLen;
}
int main()
{
while (printf("请输入字符串:\n"))
{
scanf("%s", s);
printf("最长回文长度为 %d\n\n", Manacher());
}
return 0;
}
标签:子串,int,日记,算法,id,new,拉车,mx,回文 来源: https://www.cnblogs.com/Shayndel/p/13983697.html