manacher板子 快速求最长回文串的长度

目录

原理

使用示范,本板子是加#(奇偶长度一起算)的:

 单独lamda:

OI Wiki摘录的只算单数和双数的:


原理

r记录当前最右的回文(l(左)与之对应),这样我们后来在r中偏右进行判断时,因为l r之间是回文,所以可以参照中偏左对应的位置,少判断许多次。

使用示范,本板子是加#(奇偶长度一起算)的:

d[i]表示以位置i为中心的最长回文串的半径长度

d数组的值-1即是本位置最长回文长度,原因看最下面注释。

void solve()
{
	string str, aim;
	cin >> str;
	aim += "#";
	for (int i = 0; i < str.size(); i++)
	{
		aim += str[i];
		aim += "#";
	}

	vectord(aim.size());

	//  abcba
	auto manacher = [&](string s) {
		int l = 0, r = -1;
		for (int i = 0; i < s.size(); i++)
		{
			int k = i > r ? 1 : min(d[l + r - i], r - i + 1);//左边对称相同,但不越界
			//k是半径,加了等于下一位
			//朴素算法
			while (i - k >= 0 && i + k <= s.size() && s[i - k] == s[i + k])
				k++;
			d[i] = k;
			if (i + d[i] - 1 > r)
			{
				r = i + d[i] - 1;
				l = i - d[i] + 1;
			}
		}
	};
	manacher(aim);
	int ans = 0;
	for (auto x : d)
	{
		ans = max(ans, x);
	}
    //d[i]表示i(不包括i)左右的对称的长度
	// # a # b # a #
	//		 - - - -
	// # a # b # b # a #
	//		   - - - - -
	cout << ans - 1;
}

 单独lamda:



	//  abcba
	auto manacher = [&](string s) {
		int l = 0, r = -1;
		for (int i = 0; i < s.size(); i++)
		{
			int k = i > r ? 1 : min(d[l + r - i], r - i + 1);//左边对称相同,但不越界
			//k是半径,加了等于下一位
			//朴素算法
			while (i - k >= 0 && i + k <= s.size() && s[i - k] == s[i + k])
				k++;
			d[i] = k;
			if (i + d[i] - 1 > r)
			{
				r = i + d[i] - 1;
				l = i - d[i] + 1;
			}
		}
	};

————

OI Wiki摘录的只算单数和双数的:

vector 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 + 1);
  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 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;
  }
}

你可能感兴趣的:(板子,算法,数据结构)