字符子串和字符子序列的区别
字符字串指的是字符串中连续的n个字符;如palindrome中,pa,alind,drome等都属于它的字串
而字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符;如palindrome中,plind,lime属于它的子序列,而mod,rope则不是,因为它们与字符串的字符顺序不一致。
Manacher's Algorithm
在计算机科学中,最长回文子串或最长对称因子问题是在一个字符串中查找一个最长的连续的回文的子串,例如“banana”最长回文子串是“anana”。最长回文子串并不一定是唯一的,比如“abracadabra”,没有超过3的回文子串,但是有两个回文字串长度都是3:“ada”和“aca”。在一些应用中,我们求出全部的极大回文子串(不被其他回文串包含的回文子串)。
Manacher于[1]发现了一种线性时间算法,可以在列出给定字符串中从任意位置开始的所有回文子串。并且,Apostolico, Breslauer & Galil [2]发现,同样的算法也可以在任意位置查找全部极大回文子串,并且时间复杂度是线性的。因此,他们提供了一种时间复杂度为线性的最长回文子串解法。另外,Jeuring (1994)[3], Gusfield (1997)[4]发现了基于后缀树的算法。也存在已知的高效并行算法。
最长回文子串算法不应当与最长回文子序列算法混淆。
要在线性时间内找出字符串的最长回文子串,这个算法必须利用回文和子回文的这些特点和观察
C++实现
constexpr auto MAXN = (int)7000000; char s[MAXN << 1], str[MAXN]; int RL[MAXN]; int Manacher(void) { size_t len = strlen(str); *s = '#'; for (int i = 0; i < len; i++) { s[(i << 1) + 1] = str[i]; s[(i << 1) + 2] = '#'; }len = (len << 1) + 1; int max = 1, pos, maxRight = -1; memset(RL, 0, sizeof(RL)); for (int i = 0; i < len; i++) { if (i < maxRight) RL[i] = std::min(RL[(pos << 1) - i], maxRight - i); else RL[i] = 1; while (i - RL[i] >= 0 && i + RL[i] < len && s[i - RL[i]] == s[i + RL[i]])++RL[i]; if (i + RL[i] > maxRight) { pos = i; maxRight = i + RL[i]; } max = std::max(max, RL[i] - 1); } return max; }
具体实现过程演示
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #define lson l,mid,idx<<1 #define rson mid+1,r,idx<<1|1 #define lc idx<<1 #define rc idx<<1|1 #define N 100010 #define ll long long using namespace std; char str[N],s[N]; int len[N]={0}; int manachr(){ s[0]='$'; int n=1; for(int i=0;str[i];i++)s[n++]='#',s[n++]=str[i]; s[n++]='#';s[n]='