zoukankan      html  css  js  c++  java
  • 回文子串之Manacher算法

    参考和学习的博文:https://blog.csdn.net/ggggiqnypgjg/article/details/6645824?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

    整个算法分为两步:

      1.对文本字符串做简单的预处理

      2.线性时间求出辅助数组p 及 答案

    第一:

      在原文本串的每个字符的左边都加上一个特殊字符(例如:‘#’, 字符不会在文本串出现),最后在末尾在加上一个特殊字符

      例如:

        文本串:abcd

        预处理:#a#b#c#d#

      之所以这么做是可以把原文本串变成一个长度为奇数的字符串,这样我们就可以根据奇数回文串中心对称的特点来解决

    第二:

      先说明辅助数组 p[ i ] 的含义:即从 i 个 字符 起 往右移动 p [ i ]  下可以移出以 s[ i ] 为 中心的回文串

      例如:

     

    字符串 # a # a # b # c # b #
    下标 1 2 3 4 5 6 7 8 9 10 11
    p数组 1 2 3 2 1 2 1 4 1 2 1

        以下标为3的字符 # 为例: 以他为中心的回文串显然是 #a#a# 那么他只需要往右移动三下就可以移出回文串的范围了。

      接下来讲一下怎么求 p 数组:

        先引入两个变量 mx 和 id;

        mx : 当前下标的左边的 i + p[ i ] 的 最大值

        id: mx 对应的下标

        例如 : 当循环至下标 4 时, mx = 6,  id = 3; 

        计算 p[ i ] 时 可以分两种情况:

          一:

            mx > i   -》  p[ i ] = min( p [ 2 * id - i ] , mx - i )   (这是核心)

            设 j = 2 * id - i; 显然 j  是 i 关于 id 的对称点

            可以根据这个图片理解上面的式子:

                           

        二:赋值 p [ i ] = 1

        接下来在以 i 为 中心, p [ i ] 为 起点循环向左右继续查找; 

        通过观察显然可以发现 原文本串的最长回文串的长度就是 p [ i ] 的最大值 - 1;

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N = 1e5 + 7;
     7 
     8 char s1[N], s2[N * 2];   // s1是原文本串 s2是处理过后的字符串
     9 int p[N * 2];           // 辅助数组
    10 
    11 int Manacher(char *s, int len)
    12 {
    13     int id = 1, mx = 0, res = 0;
    14     // 字符串是从1到len的
    15     for(int i = 1; i <= len; i++)
    16     {
    17         if(mx > i)   p[i] = min(p[2*id-i], mx-i);
    18         else            p[i] = 1;
    19         while(i+p[i] <= len && s[i+p[i]] == s[i-p[i]])
    20             p[i] ++;
    21         if(i+p[i] > mx) { mx = i+p[i]; id = i; }
    22         res = max(res, p[i] - 1);
    23     }
    24     return res;
    25 }
    26 
    27 int main()
    28 {
    29     scanf("%s", &s1);
    30     int lenS1 = strlen(s1);
    31     int lenS2 = 0;
    32     // 在每一个字符左右都加上'#'
    33     for(int i = 0; i < lenS1; i++)
    34     {
    35         s2[++lenS2] = '#';  // 下标是从1开始的
    36         s2[++lenS2] = s1[i];
    37     }
    38     s2[++lenS2] = '#';
    39 
    40     cout << Manacher(s2, lenS2) << endl;
    41 
    42     return 0;
    43 }
  • 相关阅读:
    实验五——循环结构学习总结
    对象判等
    一个转行的程序员给我们的忠告,很中肯
    自定义异常类
    Python入门系列(一):感言
    Python入门系列(三):基本概念
    Python入门系列(二):环境搭建(基于Windows)
    Python入门系列(四):运算符与表达式
    JQuery前奏:特性简介
    JQuery对象与DOM对象互相转换
  • 原文地址:https://www.cnblogs.com/nonameless/p/12367837.html
Copyright © 2011-2022 走看看