zoukankan      html  css  js  c++  java
  • 【字符串】 manacher算法

    Algorithm

    Task

    给定一个字符串,求其最长回文子串

    Limitations

    要求时空复杂度均为线性且与字符集大小无关。

    Solution

    考虑枚举回文串的对称轴,将其对应的最长回文子串长度 (len) 求出来,取最大值即为答案。

    首先回文串有两种,长度为奇数的和长度为偶数的,第一种的对称轴是一个字符,第二种的对称轴在两个字符之间。

    为了将两种情况统一起来,我们将原字符串的每两个相邻字符之间和首位字符前后都加上同一个不在字符集内的其他字符,例如,将 (aaa) 变成 (#a#a#a#),这样字符串的对称轴一定是一个字符了。

    定义回文半径 (r) 为对称轴到回文串边界的字符数量,也即对称轴的下标,考虑新字符串的回文半径一定是 # 和其他字符交替出现,并以 # 结尾,因此 r 一定是奇数,而其中真正的的字符数量为 (frac{r - 1}{2}),加上另一侧得字符,得到该回文串对应原字符串的回文长度为 (frac{r - 1}{2} imes 2~=~r - 1)

    我们从左到右扫描新字符串,设当前扫描到了 (i),则 (forall j in [1, ~i))(len_j) 已经被计算完毕。

    设之前的所有回文子串中,右端点最大的为 (pos),其对应对称轴为 (mid)

    分两种情况讨论。

    第一种情况,(i < pos),则 (i) 在以 (pos) 为右端点,$ mid$ 为对称轴的大回文串中。

    找到 (i) 关于 (mid) 的对称点 (j) ,若 (j) 对应的回文串的左端点不在大回文串的左侧,由于回文串的对称性,对称过去以后 (i) 的对应回文串应该与 (j) 相同,于是有 (len_i = len_j)

    否则,在回文串内部的部分一定是对称的,对于 (pos) 右侧的部分,则暴力向右匹配即可。

    第二种情况,(i geq pos),则直接进行暴力匹配。

    考虑复杂度:每次暴力匹配,(pos) 会自增 (1),而单次的复杂度是 (O(1)) 的,因此暴力匹配的总复杂度是 (O(|S|)) 的,而剩下的操作都是 (O(1)) 的因此总的时间复杂度是线性的。

    Sample

    P3805 【模板】manacher算法

    Description

    给定一个只由小写字母组成的回文串 (S),求最长回文子串长度。

    Limitations

    (|S| leq 1.1 imes 10^7)

    Solution

    板板题,依然需要注意等号的位置。

    在实现中,可以在字符串结尾添加另一个无关字符,这样可以保证匹配时不会越界,并且不用手动判断。

    Code

    #include <cstdio>
    #include <algorithm>
    
    const int maxn = 22000007;
    
    int n, ans;
    char S[maxn];
    int len[maxn], mid[maxn];
    
    void ReadStr();
    
    int main() {
      freopen("1.in", "r", stdin);
      ReadStr();
      for (int i = 1, pos = 0; i <= n; ++i) {
        if (i >= pos) {
          int l = pos = i;
          while (S[l - 1] == S[pos + 1]) { --l; ++pos; }
          len[i] = pos - i + 1;
          mid[pos] = i;
        } else {
          int j = (mid[pos] << 1) - i;
          if (len[j] < (pos - i + 1)) {
            len[i] = len[j];
          } else {
            int l = (i << 1) - pos;
            while (S[l - 1] == S[pos + 1]) { --l; ++pos; }
            len[i] = pos - i + 1;
            mid[pos] = i;
          }
        }
        ans = std::max(ans, len[i]);
      }
      qw(ans - 1, '
    ', true);
      return 0;
    }
    
    void ReadStr() {
      static char tmp[maxn];
      int _len = 0;
      do tmp[++_len] = IPT::GetChar(); while ((tmp[_len] >= 'a') && (tmp[_len] <= 'z'));
      tmp[_len--] = 0;
      for (int i = 1; i <= _len; ++i) {
        S[++n] = '#';
        S[++n] = tmp[i];
      }
      S[++n] = '#'; S[++n] = '$';
    }
    
    
  • 相关阅读:
    又搬回来了233
    2017.10.2解题报告
    2017.10.1解题报告
    Android 百度地图开发(二)--- 定位功能之MyLocationOverlay,PopupOverlay的使用
    Last_IO_Errno: 1236 Last_IO_Error: Got fatal error 1236 from master when reading data from binary lo
    [Warning] Aborted connection 11203 to db: 'ide' user: 'nuc' host: 'prd01.mb.com' (Got an error writi
    浅析地方门户网优化的方法
    xxx==null和xxx.equals(null)的区别
    Java+7入门经典
    《UNIX环境高级编程》笔记--read函数,write函数,lseek函数
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/11509744.html
Copyright © 2011-2022 走看看