• 后缀数组专题


    一、单个字符串问题

      1、重复子串

        ①可重叠最长重复子串

         分析:后缀的lcp就是子串的lcp,等价于求任意两个后缀的的最长公共前缀,任意两个后缀的最长公共前缀是这段height[]中的最小值,这个最小值一定小于整个height[]的最大值,所以结果就是height[]的最大值

            O(n)

        ②不可重叠最长重复子串(poj1743)

         分析:二分k,表示是否存在长度为k的不重叠重复子串

            然后对于height[]从前往后扫描一边,把那些相邻height[]>=k的放在一组

            易得,如果答案存在,那么必定是某一组中间的两个后缀,不可能跨组

            然后分析发现,一组中如果存在两个是不重叠的,那么他们的对应后缀长度的差应该是>=k的,所以只要找出每组中sa[]的最大值和最小值的差,判断是否大于等于K即可

            O(nlogn)

        ③可重叠的k次最长重复子串(poj3261):给定一个字符串,求至少出现K次的最长重复子串,这些子串可以重叠

           分析:和上一题方法类似,同样也是二分K,再分组,判定方法是看有没有一组的个数>=k,有就ok

            O(nlogn)

      2、子串的个数

        ①给定一个字符串,求不相同的子串的个数(spoj705)

         分析:ans=总的子串个数-重复出现的子串个数

            重复出现的子串个数反映到height里,就是所有height的和

            O(n)

      3、回文子串

         ①最长回文子串

          分析:将子串反过来接在原串的后面,中间加个'&'表示分割,先对这个新的字符串求后缀数组

             如果有回文串的话,那么一定存在两个后缀他们的前缀相同

             于是枚举每个位置k,找到它翻过去的那个点,对这两个点求他们的最长公共前缀(也就是height[]某一段的最小值,用rmq解决),这个就是回文长度的一半

             要考虑奇数/偶数,当然在每个字符中间加个'$'是个很好的办法,不需要讨论了

             O(nlogn)

      4、连续重复子串

         ①连续重复子串(poj2406):给定一个字符串L,已知这个字符串是由某个子串S重复R次得到的,求R的最大值

          分析:枚举S的长度k,当然先要判断下k是否是L长度的因子

             然后接下来判断是否可行,其实就是判断后缀1和后缀k+1的LCP是否是n-k,因为这里求最小的时候始终都有一个height[rank[1]],所以不需要rmq,只需要求height[1..k]的最小值就行

             O(n)

        ②重复次数最多的连续重复子串(poj3693):给定一个字符串,求其中一个由循环子串构成且循环次数最多的一个子串,有多个就输出最小字典序的  

         分析:枚举长度为L的小子串最多循环多少次

            那么对于位置s[0] s[L] s[2L] s[3L] ......

            那么一个重复子串肯定跨越了两个相邻的位置s[i*L]和s[(i+1)*L]

            类似①,我们去求s[i*L]和s[(i+1)*L]的lcp,那么就能求出以s[i*L]为起点的最长循环串长度

            但是问题是最优解的起点不一定是这些分界点啊

            我们考虑s[i*L]和s[(i+1)*L]的lcp,假设其%L的结果是M,那么说明后面多了M个字符,其实也说明前面少了L-M个字符

            那么我们以s[i*L-(L-M)]为起点去求lcp,这样绝对不会遗漏最优解

            时间复杂度:n/1+n/2+n/3+...+n/n=O(nlogn)

    二、两个字符串问题

      1、公共子串

         ①最长公共子串(poj2774)

          分析:首先把B串接在A串的后面,中间用'&'隔开

             求A和B的最长公共子串等价于求最长公共前缀的最大值,类似于前面的,应该是所有height[]中的最大值,但是这个height[]对应的两个后缀必须是不在同一个原串里(比较sa[]与'&'的大小关系即可)

             O(n)  

      2、子串的个数

         ①长度>=k的公共子串的个数(poj3415)

          分析:待填坑

    三、多个字符串问题

      ①给你n个字符串,求出一个最长子串,使得这个子串至少在k个字符串中出现过(poj3294)

       分析:将所有字符串串起来,中间用'&'连接,再二分长度,按照height分组,看看每组之中是否可以填满k个字符串

          O(nlogn)

      ②给你n个字符串,求在每个字符串中至少出现两次且不重叠的最长子串(spoj220)

       分析:跟上题类似,就是判断时候不同,不再赘述

      ③给定n个字符串,求出现或反转后出现在每个字符串中的最长子串

       分析:这里要额外把反转后的字符串加在后面,然后二分判断(poj3294)

    总结:1、把子串当做后缀的前缀

       2、处理多个子串或者回文串,将所有字符串加在一起(必要时要反着写),注意中间用'&'隔开

       3、处理最长公共串问题,可以转化为二分判定问题,按照height[]分组,在组里判断是个常见的方法   

                 

            

     

  • 相关阅读:
    UltraEdit程序设置添加到右键菜单
    UltraEdit加入到右键菜单中
    vim常用命令
    Linux vi命令大全
    vi/vim 计算搜寻关键字数量
    vi 删除全部内容
    vi中全选的命令或者快捷方式
    VI打开和编辑多个文件的命令
    vi/vim 查找替换使用方法
    VMware workstation 与 VMware GSX Server 的区别
  • 原文地址:https://www.cnblogs.com/wmrv587/p/5943828.html
Copyright © 2020-2023  润新知