题目要求:
对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?
,最长对称子串为s PAT&TAP s
,于是你应该输出11。
输入格式:
输入在一行中给出长度不超过1000的非空字符串。
输出格式:
在一行中输出最长对称子串的长度。
输入样例:
Is PAT&TAP symmetric?
输出样例:
11
思路:
字符串哈希:
字符串哈希全称字符串前缀哈希法,把字符串变成一个p进制数字(哈希值),实现不同的字符串映射到不同的数字。
对形如 的字符串,采用字符的ASCII码乘上 P 的次方来计算哈希值。
映射公式
即字符串str映射成值为value。
设s为下标从1开始的字符串,h[i]代表字符串s前i个字符的构成的字串的哈希值, p[i]代表k的i次方。
根据定义与公式分别求出h[i]:
则h[i] = s[1] * p[i - 1] + s[2] * p[i - 2] + ... + s[i - 1] * p[1] + s[i] * p[0]。
因为规定s下标从0开始,p[i]代表P的i次方。所以p[0] = 1。由此得:
h[0] = 0;
h[1] = s[1] * p[0] = h[1]
h[2] = s[1] * p[1] + s[2] * p[0] = h[1] * k + s[2]
h[3] = s[1] * p[2] + s[2] * p[1] + s[3] * p[0] = h[2] * k + s[3]
.
.
.
h[i - 1] = s[1] * p[i - 2] + s[2] * p[i - 3] +...+ s[i - 2] * p[1] + s[i - 1] * p[0] = h[i - 2] * k + s[i - 1];
h[i] = s[1] * p[i - 1] + s[2] * p[i - 2] + ... + s[i - 1] * p[1] + s[i] * p[0] = h[i - 1] * k + s[i]
由以上公式得出h[i] = h[i - 1] * k + s[i];
而单纯这样算很容易超出数据范围,因此对哈希值取余
有的小伙伴可能会觉得这样容易导致不同字符串有相同得hash值。
不用担心,经过实验与论证,当k取131或13331,取余mod取2的64次方时,可唯一确定一个字符串对应一个哈希值。
当我们要求字串的hash值时,由于规定h[i] 为前i个字符组成的字串的哈希值,因此可利用前缀和公式,但在这里要进行小小的变形
假设求一个字符串[l, r]之间字串的哈希值,value= h[r] - h[l] * p[r - l + 1]。
例如:求这个字符串中这个字串的哈希值,即求下标[2, 3]字串,value = h[3] - h[2] * p[3 - 2 + 1] 。
这是由于我们要讲大串与小串最后一位对齐。,因此h[l]要乘p的r-l+1次方。
本题:
输入字符串str1后,将str1赋给str2,str2前后翻转,使str1和str2翻转。这样做的目的是,为了求对称字串,判断一个字符串str1的[l, r]是对称串,我们只需判断str1的[l, r]与str2[n - r + 1, n - l + 1]的哈希值是否一致。相同则是对称字串。
记得将str1和str2设置成下标1开始的子串!!!
本题代码:
单个字符算对称串,最后答案不能为0,最小为1!!!
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 10010, P = 131;
int n, res; //res为最终答案
ULL h1[N], h2[N], p[N]; //h1[]为str1对应哈希值,h2[]为str2对应哈希值,p[i]为P的i次方
string str1, str2;
ULL get(int l, int r, ULL h[])
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main(){
getline(cin, str1); //输入
n = str1.size();
str1 += '.';
str2 = str1, reverse(str2.begin(), str2.end()); //翻转后字符串str2下标已从1开始
for(int i = str1.size() - 2; i >= 0; i --) str1[i + 1] = str1[i]; //将str1下标设为从1开始
p[0] = 1;
for(int i = 1; i <= n; i ++) //哈希赋值
{
p[i] = p[i - 1] * P;
h1[i] = h1[i - 1] * P + str1[i];
h2[i] = h2[i - 1] * P + str2[i];
}
for(int i = 1; i <= n; i ++)
for(int j = i; j <= n; j ++)
if(get(i, j, h1) == get(n - j + 1, n - i + 1, h2)) //比较
res = max(res, j - i + 1); //取最大值
cout << res;
return 0;
}