zoukankan      html  css  js  c++  java
  • Manacher算法操作详解

    Manacher

    问题引入

    • 求一个长度为 n n n的字符串中回文子串的个数?
    • (或:求一个长度为 n n n的字符串中最长的回文子串的长度?)
    • 回文串:一个正读和反读相同的字符串,称之为回文串。

    用已有的知识

    • 算法一:枚举开头,枚举结尾,得到一个串,再扫一遍判断是否为回文串,若是,答案加 1 1 1,时间复杂度 O ( n 3 ) O(n^3) O(n3)
    • 算法二:枚举开头,枚举结尾,得到一个串,用字符串哈希判断其是否为回文串,若是,答案加 1 1 1,时间复杂度 O ( n 2 ) O(n^2) O(n2)
    • 算法三(对下文有用):枚举回文串的对称中心,分长度为奇或偶两种情况,分别向两端延伸,若延伸到的最大长度为 s s s(以奇数的情况为例,最大扩展到 s t i − s + 1 st_{i-s+1} stis+1 s t i + s − 1 st_{i+s-1} sti+s1),那么答案加上 s s s,时间复杂度 O ( n 2 ) O(n^2) O(n2)
    • 枚举回文串的对称中心,分长度为奇或偶两种情况,分别二分能延伸的长度,用字符串哈希判断,若延伸到的最大长度为 s s s(以奇数的情况为例,最大扩展到 s t i − s + 1 . . s t i + s − 1 st_{i-s+1}..st_{i+s-1} stis+1..sti+s1),那么答案加上 s s s,时间复杂度 O ( n log ⁡ 2 n ) O(nlog_2 n) O(nlog2n)

    提出疑问

    • 有没有更快的方法,比如 O ( n ) O(n) O(n)
    • 有没有更简洁的方法,不用哈希?
    • 答案是:有!

    算法介绍

    • 算法名称:Manacher’s Algorithm
    • 主要思路是用已经计算出的回文子串,利用它回文的特性,对即将计算的回文子串提供一定的帮助。
    • 需要记录 l , r l,r l,r表示已经找出的回文子串中,右端点最靠右的回文子串所在区间,
    • 初始值分别为 0 , − 1 0,-1 0,1
    • 以下以长度为奇数的情况为例,介绍算法操作流程。
    • 1 − n 1-n 1n依次枚举字符串的对称中心,对于每个 i i i,考虑向两边扩展,扩展的最长长度为 d i d_i di(也就是最大扩展到 s t i − d i + 1 . . s t i + d i − 1 st_{i-d_i+1}..st_{i+d_i-1} stidi+1..sti+di1)。
    • 定义朴素算法为上文“用已有的知识”中的算法三,
    • 那么我们考虑优化这个朴素算法,算法的核心是利用已有的 d d d来加速计算当前的 d i d_i di
    • 分两种情况:
    • 一、 i > r i>r i>r(若长度为偶数则 i ≥ r i≥r ir
    • 直接调用朴素算法计算 d i d_i di
    • 二、 i ≤ r i≤r ir(若长度为偶数则 i < r i<r i<r
    • 即说明 i i i在回文子串 s t l . . s t r st_l..st_r stl..str内,那么找到 i i i在这个回文子串中对称的点 j j j
      j = l + r − i j=l+r-i j=l+ri
    • 因为对称,所以巧妙地利用这个性质, d i = d j d_i=d_j di=dj
    • 思考:这样是正确的吗??
    • 其实不然——
    • 因为以为中心 j j j的回文子串,左边界可能超出 l l l,那么对称过去到了 i i i就不在大回文子串 s t l . . s t r st_l..st_r stl..str内了,不能保证也回文,所以
      d i = m i n ( d j , r − i + 1 ) d_i=min(d_j,r-i+1) di=min(dj,ri+1)
    • 同理,对 i i i而言,以它为中心的实际最大回文子串可能右边界超出 r r r,那么 d j d_j dj是计算不到的,所以,在上式的基础上,再次调用朴素算法。
    • 至此,这个问题完美解决。

    时间复杂度分析

    • 算法是两重循环,看似复杂度极限会是 O ( n 2 ) O(n^2) O(n2)???
    • 其实并不如此,实际上,它的复杂度十分优秀。
    • 观察调用朴素算法的条件,发现每次朴素算法的调用,只会判断还没有被回文子串覆盖过的字符,也就是说,每个字符只会被朴素算法进行一次,
    • 这样下来,时间复杂度是均摊 O ( n ) O(n) O(n)的。
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    SharePoint Portal Server与SharePoint Services之间的关系
    配置Microsoft Visual SourceSafe 2005的局域网/Internet访
    Maven创建Web项目(idea)
    Maven入门(idea)
    Windows下搭建Vue脚手架CLI
    关于wince中的全屏显示
    ubuntu右键添加打开终端的快捷菜单[转]
    将CString转换成string ...
    090606日记
    Java中的InputStream和OutputStream
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910038.html
Copyright © 2011-2022 走看看