4. 既然是O(n)的算法,求解pnum[i]时,pnum[i-1]等已知
可以记录下右端点r最靠右,即pnum[i]+i最大时的i和p[i]+i
$ # a # b # b # a #
i r id = i, mx = r = i + pnum[i]
int mx =0, id;if(p[i]+i>mx)
mx = p[i]+i, id = i;
5. 下一次匹配时可以参考mx以及id
$ # a # b # b # a #
mx' i' id i mx
当i < mx时,i' = id - (i - id) = 2*id - i
pnum[i']已知,由回文串的性质,pnum[i] = pnum[i']
当然,pnum[i]不能大于mx - i,因为超出该范围后不能利用回文串的性质
voidManacher(int&n){
str[0]='$';
str[1]='#';for(int i =0; i < n; i++)
str[(i <<1)+2]= s[i], str[(i <<1)+3]='#';
n =2* n +2;
str[n]=0;int mx =0, id;for(int i =1; i < n; i++){
pnum[i]= mx > i ?min(pnum[2* id - i], mx - i):1;// while循环部分只是普通的暴力过程while(str[i - pnum[i]]== str[i + pnum[i]])
pnum[i]++;if(pnum[i]+ i > mx)
mx = pnum[i]+ i, id = i;}}
6. 可以发现,所有
p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
这一部分的回文串都是利用了之前相同的回文串,排除这一部分似乎就可以得到本质不同的回文子串了
因此我们在while循环部分添加如下代码
set<pair<ull, ull>> strSet;while(str[i-pnum[i]]== str[i+pnum[i]]){
pnum[i]++;// ============================寻找本质不同子串// 排除 #if(pnum[i]<2)continue;int l = i - pnum[i]+1;int r = i + pnum[i]-1;// 排除 a # a // 保留 # a # a #if(str[l]!='#')continue;
strSet.insert({l, r});// ============================}
7. 然而...
$ # a # b # b # a #
1 1 1 2 2 2
此时相同的1串和2串都会被加入set中
此时需要利用字符串HASH去除本质重复的情况
这里就不写了,下面的题会用到