zoukankan      html  css  js  c++  java
  • Manacher模板( 线性求最长回文子串 )

     模板

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int maxn = 2e5 + 10;
    char s[maxn], sNew[maxn<<1];
    int p[maxn<<1], id, mx=0;
    int L, R; //回文串在原串的左右端点位置
    
    int Init()
    {
        int len = strlen(s);
        sNew[0] = '$';
        sNew[1] = '#';
        int j = 2;
        for (int i = 0; i < len; i++){
            sNew[j++] = s[i];
            sNew[j++] = '#';
        }
        sNew[j] = '';
        return j;
    }
    
    int Manacher()
    {
        int len = Init();
        int max_len = -1;
        mx = 0;
        for (int i = 1; i < len; i++){
            if (i < mx) p[i] = min(p[2 * id - i], mx - i);
            else p[i] = 1;
    
            ///在对象不是字符串时候,原本为了防止越界是左有'$'
            ///右有'',现在右边就没有'',需要人为填充替代!
    
            while (sNew[i - p[i]] == sNew[i + p[i]]) p[i]++;
    
            if (mx < i + p[i]){
                id = i;
                mx = i + p[i];
            }
    
            //max_len = max(max_len, p[i] - 1);
    
    ////      如果题目不要求输出回文串在原串的位置,则用下面代码更新答案
            if(max_len < p[i]){ ///这里L、R记录的是最长回文子串在原串的左右端点
                max_len = p[i];
                L = (i - p[i])>>1;
                R = (i + p[i] - 4)>>1; ///R = (i + p[i])/2 -2;
            }
    
        }
        return max_len;
    
    ///    最后如若需要找到的回文串则是
    ///    for(int i=(id-mx+1);i<=(id+mx-1);i++)
    ///         if(sNew[i]!='#'&&sNew[i]!='$') ///注意你设置的开头符号和填充符号,不同则需要修改
    ///             putchar(sNew[i]);
    }
    View Code

    p[i]-1 为以 i 为中心的回文长度

    p[i]/2 表示回文半径

    i%2==0 表示这个位置为字符,i/2-1 表示原字符串的位置

    i%2==1 表示为字符中间,这两边的字符在原字符串的位置分别为 i/2-1 和 i/2

    问题提出 : 给出一个串,要求在O(n)时间复杂度内计算出最长的回文子串

    分析参考==> https://www.61mon.com/index.php/archives/181/  or  https://www.felix021.com/blog/read.php?2040

    相关题目 :

    HDU 3068

    题意 : 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.

    分析 : 模板题

    POJ 3974

    题意 : 给出一个串,求最长回文子串

    分析 : 还是模板题

    ③ 吉哥系列故事――完美队形II

    题意 : 中文题就不复述了

    分析 : 实际上还是模板题,只要在回文判断两边相等的代码上加上递增这一条件即可

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include<stdio.h>
    using namespace std;
    const int maxn = 1e5 + 10;
    const int INF  = 0x3f3f3f3f;
    int s[maxn], s_new[maxn<<1];
    int p[maxn<<1], id, mx=0;
    int len;
    int Init()
    {
        s_new[0] = -1;
        s_new[1] = INF;
        int j = 2;
        for (int i = 0; i < len; i++){
            s_new[j++] = s[i];
            s_new[j++] = INF;
        }
        return j;  // 返回 s_new 的长度
    }
    
    int Manacher()
    {
        int len = Init();  // 取得新字符串长度并完成向 s_new 的转换
        int max_len = -1;  // 最长回文长度
        mx = 0;
        for (int i = 1; i < len; i++){
            if (i < mx) p[i] = min(p[2 * id - i], mx - i);  // 需搞清楚上面那张图含义, mx 和 2*id-i 的含义
            else p[i] = 1;
    
            while (s_new[i - p[i]] == s_new[i + p[i]]
                   && s_new[i - p[i]] <= s_new[i - p[i] + 2]) p[i]++;// 不需边界判断,因为左有'$',右有''
    
            if (mx < i + p[i]){
                id = i;
                mx = i + p[i];
            }
    
            max_len = max(max_len, p[i] - 1);
        }
        return max_len;
    ///    最后如若需要找到的回文串则是
    ///    for(int i=(id-mx+1);i<=(id+mx-1);i++)
    ///         if(s_new[i]!='#'&&s_new[i]!='$')
    ///             putchar(s_new[i]);
    }
    
    int main(void)
    {
        int nCase;
        scanf("%d", &nCase);
        while(nCase--){
            scanf("%d", &len);
            for(int i=0; i<len; i++) scanf("%d", &s[i]);
            printf("%d
    ", Manacher());
        }
        return 0;
    }
    View Code

    HDU 3294

    题意 : 首先给出一个字符,代表所有的字符真正对应的都往前移动,例如给出'b'那么真正的'a'就是'b','b'就是真正的'c',后来再给你一个串,问你通过上面转变后的最长回文子串是什么,给出首尾位置以及具体的回文序列

    分析 : 这里多了一步需要具体定位回文,那么根据算法的具体意义,可以知道最长回文串的起始位置L=(i-p[i])/2,R=(i+p[i])/2-2,每一次更新答案都去更新L、R即可

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int maxn = 2e5 + 10;
    char s[maxn], sNew[maxn<<1];
    int p[maxn<<1], id, mx=0;
    int L, R; //回文串在原串的左右端点位置
    
    int Init()
    {
        int len = strlen(s);
        sNew[0] = '$';
        sNew[1] = '#';
        int j = 2;
        for (int i = 0; i < len; i++){
            sNew[j++] = s[i];
            sNew[j++] = '#';
        }
        sNew[j] = '';
        return j;
    }
    
    int Manacher()
    {
        int len = Init();
        int max_len = -1;
        mx = 0;
        for (int i = 1; i < len; i++){
            if (i < mx) p[i] = min(p[2 * id - i], mx - i);
            else p[i] = 1;
    
            ///在对象不是字符串时候,原本为了防止越界是左有'$'
            ///右有'',现在右边就没有'',需要人为填充替代!
    
            while (sNew[i - p[i]] == sNew[i + p[i]]) p[i]++;
    
            if (mx < i + p[i]){
                id = i;
                mx = i + p[i];
            }
    
            //max_len = max(max_len, p[i] - 1);
    
    ////      如果题目不要求输出回文串在原串的位置,则用下面代码更新答案
            if(max_len < p[i]){ ///这里L、R记录的是最长回文子串在原串的左右端点
                max_len = p[i];
                L = (i - p[i])>>1;
                R = (i + p[i] - 4)>>1; ///R = (i + p[i])/2 -2;
            }
    
        }
        return max_len;
    
    ///    最后如若需要找到的回文串则是
    ///    for(int i=(id-mx+1);i<=(id+mx-1);i++)
    ///         if(sNew[i]!='#'&&sNew[i]!='$') ///注意你设置的开头符号和填充符号,不同则需要修改
    ///             putchar(sNew[i]);
    }
    
    int mp[27];
    
    int main(void)
    {
        char letter;
        while(~scanf(" %c", &letter)){
    
            int num = letter - 'a';
            for(int i=0; i<26; i++)
                mp[(i+num)%26] = i;
    
            scanf("%s", s);
    
            int len = strlen(s);
            for(int i=0; i<len; i++) s[i] = mp[s[i]-'a']+'a';
    
            if(Manacher() > 2){
                printf("%d %d
    ", L, R);
                for(int i=L; i<=R; i++)
                     putchar(s[i]);
                puts("");
            }else puts("No solution!");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    div布局改进treeview导航
    WEB框架研究笔记八(HIBERNATE)
    WEB框架研究笔记四(Spring Framework)
    WEB框架研究笔记二(Extjs调用Struts)
    WEB框架研究笔记九(PowerDesigner)
    WEB框架研究笔记七(Spring2+struts2)
    WEB框架研究笔记十(JPA)
    WEB框架研究笔记11(第一阶段完成)
    WEB框架研究笔记五(Spring Aop)
    WEB框架研究笔记三(连接数据库)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7598206.html
Copyright © 2011-2022 走看看