POJ--3974 Palindrome(字符串hash/manacher)
记录
23:30 2024-2-7
↑这个时间不准确 因为当时忘记录了
1. 字符串hash(会超时T-T)
点击查看代码
#include<iostream>
#include<vector>
#include<stdio.h>
#include<string.h>
using namespace std;
void palindrome(string s) {
unsigned long long prefixHash[s.size() + 1], revserHash[s.size() + 1], p[s.size() + 1];
memset(prefixHash, 0, sizeof(prefixHash));
memset(revserHash, 0, sizeof(revserHash));
memset(p, 0, sizeof(p));
p[0] = 1;
for(int i = 1; i < s.size(); i++) {
// [1 ~ i]
prefixHash[i] = prefixHash[i - 1] * 131 + s[i] - 'a' + 1;
p[i] = p[i - 1] * 131;
}
for(int i = s.size() - 1; i >= 1; i--) {
// [s.size() - i ~ i] 逆向计算
revserHash[i] = revserHash[i + 1] * 131 + s[i] - 'a' + 1;
}
// 枚举可能的中心位置
int begin = 1, maxSize = 1;
for(int i = 1; i < s.size(); i++) {
int lp = 1, rp = min(i, (int)s.size() - i);
int lq = 1, rq = min(i, (int)s.size() - i);
// 二分法寻找
while(true) {
if(lp > rp) break;
int midp = (lp + rp) / 2;
//if(2 * mid < maxSize) break;
if(i - midp - 1 < 0 || i + midp + 1 > s.size()) {
rp = midp - 1;
continue;
}
// s[i - midp ~ i] = reverse(s[i ~ i + midp])
// 对于prefixHash f[r] - f[l-1] * p[r-l+1]
// 对于reverseHash f[l] - f[r+1] * p[r-l+1]
if(prefixHash[i] - prefixHash[i - midp - 1] * p[midp + 1] ==
revserHash[i] - revserHash[i + midp + 1] * p[midp + 1]) {
lp = midp + 1;
if(2 * midp + 1 > maxSize) {
maxSize = 2 * midp + 1;
begin = i - midp;
}
} else {
rp = midp - 1;
}
}
while(true) {
if(lq > rq) break;
int midq = (lq + rq) / 2;
if(i - midq - 1 < 0 || i + midq > s.size()) {
rq = midq - 1;
continue;
}
// s[i - midq ~ i - 1] = reverse(s[i ~ i + midq - 1])
if(prefixHash[i - 1] - prefixHash[i - midq - 1] * p[midq] ==
revserHash[i] - revserHash[i + midq] * p[midq]) {
lq = midq + 1;
if(2 * midq > maxSize) {
maxSize = 2 * midq;
begin = i - midq;
}
} else {
rq = midq - 1;
}
}
}
cout << maxSize << endl;
}
int main() {
string s;
int i = 0;
while (cin >> s) {
if(s.compare("END") == 0) break;
// 为了方便处理,加一个空格
s = ' ' + s;
i++;
printf("Case %d: ", i);
palindrome(s);
}
}
2. manacher算法
点击查看代码
// manacher
#include<iostream>
#include<vector>
#include<stdio.h>
#include<string.h>
using namespace std;
int longestPalindrome(string s) {
int n = s.size();
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 + 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<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;
}
}
int begin = 0, maxSize = 1;
for(int i = 0; i < n; i++) {
if(2 * d1[i] - 1 > maxSize) {
maxSize = 2 * d1[i] - 1;
begin = i - d1[i] + 1;
}
if(2 * d2[i] > maxSize) {
maxSize = 2 * d2[i];
begin = i - d2[i];
}
} ;
return maxSize;
}
int main() {
int i = 0;
string s;
while (cin >> s) {
if(s.compare("END") == 0) break;
i++;
printf("Case %d: ", i);
cout << longestPalindrome(s) << endl;
}
}