回文串算法之-manacher

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_40438165/article/details/102627808

\quad 给定一个字符串 s = " a b a b a b c " s="abababc" ,求这个字符串有多少个回文串或者最长回文串是哪个。我用 d 1 [ i ] d_1[i] 是以i为中心长度为奇数的回文串个数, d 2 [ i ] d_2[i] 是以i为中心长度为偶数的回文串个数,则对字符串s而言, d 1 [ 0 ] = 1 ( a ) , d 1 [ 1 ] = 2 ( b , a b a ) , d 1 [ 2 ] = 3 ( a , b a b , a b a b a ) , d 2 [ i ] = 0 ( ) d_1[0]=1(a),d_1[1]=2(b,aba),d_1[2]=3(a,bab,ababa),d_2[i]=0(没有长度为偶数的回文串) 。对于字符串 t = " c b a a b d " t="cbaabd" d 2 [ 0 ] = d 2 [ 1 ] = d 2 [ 2 ] = 0 , d 2 [ 3 ] = 2 ( a a , b a a b ) d_2[0]=d_2[1]=d_2[2]=0,d_2[3]=2(aa,baab) 。用最朴素的枚举法可以在 O ( n 2 ) O(n^2) 内求出 d 1 [ i ] , d 2 [ i ] d_1[i],d_2[i] ,程序如下:

#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
	string s; cin >> s;
	int n = s.length();
	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]++;
	  }
	}
	for(int i = 0; i < n; i++) cout << d1[i] << " " << d2[i] << endl;
	return 0;
}
  • d 1 [ i ] + d 2 [ i ] d_1[i]+d_2[i] 是以i为中心的回文串个数
  • s u m ( d 1 [ i ] + d 2 [ i ] ) sum(d_1[i]+d_2[i]) 是字符串总的回文串个数
  • m a x ( m a x ( d 1 [ i ] 2 1 ) , m a x ( d 2 [ i ] 2 ) ) max(max(d_1[i]*2-1), max(d_2[i]*2)) 为字符串最长回文串长度

\quad 可见,如果求出 d 1 [ i ] , d 2 [ i ] d_1[i],d_2[i] ,所有关于字符串的问题都将迎刃而解。但上面朴素的解法未免太过低效,需要更快的解法,于是便有了manacher算法。

#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
	string s; cin >> s;
	int n = s.length();
	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;
	  }
	}
	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;
	  }
	}
	for(int i = 0; i < n; i++) cout << d1[i] << " " << d2[i] << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40438165/article/details/102627808
今日推荐