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;
    }
}
posted @ 2024-02-08 23:26  57one  阅读(4)  评论(0编辑  收藏  举报