• 51nod1089(最长回文子串之manacher算法)


    题目链接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1089

    题意:中文题诶~

    思路: 我前面做的那道回文子串的题目是枚举中间字符O(n^2)时间过的,不过这题字符串长度限制为1e5,O(n^2)肯定会超时啦;

    有个叫 manacher 的算法是时间复杂度为 O(n), 本题就是 manacher 模板题啦;

    我们先看一下 manacher 算法这个东东;

    首先回文串匹配奇数长度和偶数长度操作是不一样的, 我们可以在每个字符的两边都加上一个特殊字符 '#', 那么无论原串是长度是奇数还是偶数都会编程奇数长度,并且它的所有回文子串也都变成了奇数长度. 因为对于长度为 len 的字符串 str 我们要使每个字符两边都有一个 '#' 字符,需加 len+1 个 '#' 字符, 那么改变后的字符串 s 长度为 2*lne+1, 其必为奇数;那么现在我们只需要处理奇数的情况了;

    我们在用 vis 数组存储以i中心的最大回文串的回文半径(包括 s[i] 字符),那么i对应的原串 str 的回文串长度为 vis[i]-1. 因为str中该回文串长度为 2*vis[i]-1, 其中有 vis[i]个'#'字符嘛, 那么我们只要求出所有 vis[i], 那么答案也就知道了啦;

    我们再维护两个变量 id 为当前最长回文子串的中心位置, mx 为其右边界位置;

    那么对于当前 i (我们是从前往后求 vis 的, vis[id] 已知, vis[i]未知, 所以 i 一定是在 id 后面的) 我们可以分情况讨论:

    对于 mx>i 的情况, 即 i 字符在当前最大回文串里面. 我们可以找到 i 关于 id 的对称位置 j=2*id-i , 若 vis[j] <= mx-i 即以 j 位置为中心的回文串最左端没有超出最大回文串的范围, 即以 j 为中心 和以 i 为中心的最大回文子串都在以 id 为中心的那个回文串里面, 那么由回文串的对称性我们可以知道这两个字符串是一样的, 所以有 vis[i]=vis[j];

    如果vis[j] > mx-i, 即以 j 为中心的最大回文子串超出了最大回文子串的范围, 那么 vis[i]>=mx-i, 对于更长的范围就需要我们一个个去匹配了啦;

    对于 mx<i 的情况我们并没有什么信息可以利用, 所以需要重新匹配~

    代码:

     1 #include <bits/stdc++.h>
     2 #define MAXN 200010
     3 using namespace std;
     4 
     5 int main(void){
     6     char s[MAXN], str[MAXN];
     7     int vis[MAXN], j=0;
     8     memset(vis, 0, sizeof(vis));
     9     scanf("%s", str);
    10     for(int i=0; str[i]!=''; i++){ //在每个字符的两边添加一个特殊字符'#'
    11         s[j++]='#';
    12         s[j++]=str[i];
    13     }
    14     s[j++]='#', vis[0]=1;
    15     s[j++]='';
    16     int len=j-1, mx=0, id=0, ans=0; //**id表示当前最大回文子串的中心位置, mx表示当前最大回文子串的最右端位置, ans表示当前已知的最大回文串长度
    17     for(int i=1; i<len; i++){
    18         if(mx>i){ //i在当前最大回文串内的情况
    19             vis[i]=min(mx-i, vis[2*id-i]);
    20         }else{
    21             vis[i]=1;
    22         }
    23         while(s[i-vis[i]]==s[i+vis[i]]&&i>=vis[i]){ //注意边界
    24             vis[i]++; //**匹配没有可利用信息的字符
    25         }
    26         if(vis[i]+i>mx){ //**更新id和mx的值
    27             id=i;
    28             mx=i+vis[i];
    29         }
    30         ans=max(ans, vis[i]); //**更新ans
    31     }
    32     printf("%d
    ", ans-1);
    33     return 0;
    34 }

    我们通过代码也可以发现其一直都在往后匹配, 大概可以确定其时间复杂度为O(n)啦~ 

  • 相关阅读:
    使用PDO连接数据库
    ES6 promise
    弹框小三角
    封装弹窗功能
    css3 省略号
    使mac支持NTFS读写问题
    Vue 打包 build 前需要修改哪些配置和路径
    eslint配置大全
    在elementUI中使用 el-autocomplete 实现远程搜索的下拉框
    element-UI table自定义表头
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/6215927.html
Copyright © 2020-2023  润新知