• AcWing:139. 回文子串的最大长度(字符串Hash + 前缀和 + 后缀和 + 二分)


    如果一个字符串正着读和倒着读是一样的,则称它是回文的。

    给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。

    输入格式

    输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。

    输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。

    输出格式

    对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。

    每个输出占一行。

    输入样例:

    abcbabcbabcba
    abacacbaaaab
    END
    

    输出样例:

    Case 1: 13
    Case 2: 6

    算法: 字符串Hash + 前缀和 + 后缀和 + 二分

    注意:其中的二分mid的取值是 (l + r + 1) >> 1,这个是有含义的,我之前写了一些博客,可供参考 ——> https://www.cnblogs.com/buhuiflydepig/p/11291541.html

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 1e6+5;
    const int P = 13;
    
    ll prefix[maxn], suffix[maxn];      //前后缀和
    char str[maxn];     
    ll p[maxn];     
    
    void init() {
        p[0] = 1;
        for(int i = 1; i <= 1000000; i++) {
            p[i] = p[i - 1] * P;        //P进制的值位
        }
    }
    
    void setFix(char *s) {
        int len = strlen(s + 1);
        prefix[0] = suffix[len + 1] = 0;        //注意,这里需要初始话
        for(int i = 1; i <= len; i++) {
            prefix[i] = prefix[i - 1] * P + s[i] - 'a' + 1;
        }
        for(int i = len; i >= 1; i--) {
            suffix[i] = suffix[i + 1] * P + s[i] - 'a' + 1;
        }
    }
    
    ll Hash1(int l, int r, ll *arr) {       //前缀和计算区间的Hash值
        return arr[r] - arr[l - 1] * p[r - l + 1];    
    }
    
    ll Hash2(int l, int r, ll *arr) {       //后缀和计算区间的Hash值
        return arr[l] - arr[r + 1] * p[r - l + 1];
    }
    
    int main() {
        init();
        int cas = 0;
        while(true) {
            scanf("%s", str + 1);
            if(strcmp(str + 1, "END") == 0) {
                break;
            }
            setFix(str);
            int ans = 0;
            int len = strlen(str + 1);
            for(int i = 1; i <= len; i++) {
                int l = 0, r = min(i - 1, len - i);
                while(l < r) {
                    int mid =(l + r + 1) >> 1;      //二分长度,以i为中间点
                    if(Hash1(i - mid, i - 1, prefix) == Hash2(i + 1, i + mid, suffix)) {
                        l = mid;
                    } else {
                        r = mid - 1;
                    }
                   
                }
                ans = max(ans, l << 1 | 1);     //第一个二分的是奇数的回文串,所以这里需要加一
                l = 0, r = min(i - 1, len - i + 1);     //这里包括i
                while(l < r) {
                    int mid = (l + r + 1) >> 1;
                    if(Hash1(i - mid, i - 1, prefix) == Hash2(i, i + mid - 1, suffix)) {
                        l = mid;
                    } else {
                        r = mid - 1;
                    }
                }
                ans = max(ans, l << 1);     //这里是偶数的回文串
            }
            printf("Case %d: %d
    ", ++cas, ans);
        }
        return 0;
    }
  • 相关阅读:
    Linux多线程Pthread学习小结
    TCP三次握手/四次挥手
    内存管理内幕
    Delphi 中分发设计时包
    一个小的算法问题解决
    写了一个验证数字范围的正则表达式
    用 XML 文件持久化和恢复图片信息
    string.Empty 和 "" 并不总是可以互换的
    博客园用的 FreeTextBox 有 bug
    乱花渐欲迷人眼。。。
  • 原文地址:https://www.cnblogs.com/buhuiflydepig/p/11294118.html
Copyright © 2020-2023  润新知