zoukankan      html  css  js  c++  java
  • [hdu3068 最长回文]Manacher算法,O(N)求最长回文子串

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068

    题意:求一个字符串的最长回文子串

    思路:

    • 枚举子串的两个端点,根据回文串的定义来判断其是否是回文串并更新答案,复杂度O(N3)。
    • 枚举回文串的对称轴i,以及回文半径r,由i和r可确定一个子串,然后暴力判断即可。复杂度O(N2)。
    • 在上一步的基础上,改进判断子串是否是回文串的算法。记fi(r)=(bool)以i为对称轴半径为r的子串是回文串,fi(r)的值域为{0, 1},显然fi(r)是关于r的单调函数,于是可以二分r,然后用字符串hash在O(1)的时间内判断子串是否是回文串,总复杂度O(NlogN)。
    • 虽然O(NlogN)的复杂度已经非常不错了,但还有线性的算法---Manacher算法。

    Manacher算法:维护两个值r和id,r是以前的回文串的最大右边界,id是其对应的下标,如果当前考虑的对称轴i小于等于r,那么从i到r这一段子串是否可以和i左边的子串构成回文串(或者说最长能有多长)其实在之前是已经计算过了的(或者说计算出了一部分),因为将i作关于id的对称点i'=2*id-i,就不难发现i'周围若干字符和i周围若干字符是对应相同的,这是Manacher算法的核心之处,可以用i'的最大回文半径来更新i的最大回文半径,利用这个性质就能做到线性的复杂度。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    #pragma comment(linker, "/STACK:10240000")
    #include <bits/stdc++.h>
    using namespace std;
    
    #define X                   first
    #define Y                   second
    #define pb                  push_back
    #define mp                  make_pair
    #define all(a)              (a).begin(), (a).end()
    #define fillchar(a, x)      memset(a, x, sizeof(a))
    
    typedef long long ll;
    typedef pair<int, int> pii;
    
    #ifndef ONLINE_JUDGE
    namespace Debug {
    void print(){cout<<endl;}template<typename T>
    void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
    void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>
    void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
    }
    #endif // ONLINE_JUDGE
    template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}
    template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}
    /* -------------------------------------------------------------------------------- */
    
    const int maxn = 3e5 + 7;
    
    /** 求字符串每个位置的最大回文半径,在字符串中找最长回文子串 **/
    struct Manacher {
        int p[maxn];/** 回文半径 **/
        char s[maxn];
        void init(char str[]) {
            strcpy(s, str);
            int n = strlen(s);
            s[n * 2 + 1] = 0;
            for (int i = n * 2; i; i -= 2) {
                s[i] = '#';
                s[i - 1] = s[i / 2 - 1];
            }
            s[0] = '#';
        }
        /** 求每个点的最大回文半径 **/
        void work() {
            int r = 0, id = 0;
            p[0] = 1;
            for (int i = 1; s[i]; i ++) {
                p[i] = i <= r? min(r - i + 1, p[2 * id - i]) : 1;
                if (p[i] >= r - i + 1) {
                    r = (id = i) + p[i] - 1;
                    while (2 * i - r - 1 >= 0 && s[r + 1] == s[2 * i - r - 1]) {
                        r ++;
                        p[i] ++;
                    }
                }
            }
        }
        /** 求最长回文串的长度 **/
        int solve() {
            work();
            int ans = 1;
            for (int i = 0; s[i]; i ++) {
                ans = max(ans, p[i] - 1);
            }
            return ans;
        }
    };
    Manacher solver;
    
    char s[maxn];
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif // ONLINE_JUDGE
        while (~scanf("%s", s)) {
            solver.init(s);
            printf("%d
    ", solver.solve());
        }
        return 0;
    }
    
  • 相关阅读:
    Gitcafe绑定自定义域名
    如何优雅地使用Sublime Text
    使用Hexo搭建专属Blog
    How to Use Android ADB Command Line Tool
    雷军北大15分钟演讲:我至少有胆量去想(转)
    浅谈android中的目录结构
    react里 MD5加密
    git忽略相应文件夹,不上传
    antd-mobile的按需加载
    当react 项目使用px2rem
  • 原文地址:https://www.cnblogs.com/jklongint/p/4780558.html
Copyright © 2011-2022 走看看