【我的板子】manacher

问题描述

给定一个字符串s,找出所有(i,j)使得s[i……j]为回文串。(回文串就是正看倒看都一样的串)

一、朴素算法

分该回文串是奇数串还是偶数串,遍历中心位向两边延伸

vector<int> d1(n), d2(n);
for (int i = 0; i < n; i++) {
  d1[i] = 1;
  while (0 <= i - d1[i] && i + d1[i] < n && s[i - d1[i]] == s[i + d1[i]]) {
    d1[i]++;
  }

  d2[i] = 0;
  while (0 <= i - d2[i] - 1 && i + d2[i] < n &&
         s[i - d2[i] - 1] == s[i + d2[i]]) {
    d2[i]++;
  }
}

二、manacher算法

z函数思想一样
,代码也基本一样,思想就是通过利用之前已求出来的值来计算当前值

分奇偶处理时

奇回文字符串

vector<int> d1(n);
for (int i = 0, l = 0, r = -1; i < n; i++) {
  int k = (i > r) ? 1 : min(d1[l + r - i], r - i);
  while (0 <= i - k && i + k < n && s[i - k] == s[i + k]) {
    k++;
  }
  d1[i] = k--;
  if (i + k > r) {
    l = i - k;
    r = i + k;
  }
}

偶回文字符串 (假定和第i个相等的字符在i-1的位置)

vector<int> d2(n);
for (int i = 0, l = 0, r = -1; i < n; i++) {
  int k = (i > r) ? 0 : min(d2[l + r - i + 1], r - i + 1);
  while (0 <= i - k - 1 && i + k < n && s[i - k - 1] == s[i + k]) {
    k++;
  }
  d2[i] = k--;
  if (i + k > r) {
    l = i - k - 1;
    r = i + k;
  }
}

优化算法

我们先做一个预处理,将原字符串每个间隙都用’#'隔开,这样的话,我们就不用分奇偶两种情况讨论了。比如
原串:a b a b a b c
先串:# a # b # a # b # a # b # c #

为什么不用分奇偶讨论了呢

设m是原串回文串的长度
当m时奇数时,比如是a b a,这时现回文字符串# a # b # a #的长度要比原回文字符串的长度大m+1(多了#的个数),所以现回文字符串的长度是2*m+1,是奇数。
当m时偶数时,比如是a b b a,这时现回文字符串# a # b # b a #的长度还是比原回文字符串的长度大m+1(多了#的个数),所以现回文字符串的长度是2*m+1,还是奇数。
总之,现回文字符串的长度会一直是奇数,可以直接按分奇偶处理时的奇数法处理


//预处理
stirng s,str;cin>>s;
int len=s.size();
for(int i=0;i<=2*len;++i)
{	if(i&1)str[i]=s[i/2];
	else str[i]='#';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值