zoukankan      html  css  js  c++  java
  • SA学习笔记

    SA算法入门

    后缀数组是什么?

    以下用(S_i)表示字符串S的[i...n]子串部分
    对于一个字符串S的所有后缀,即所有 (S_i), 按字典序进行排序

    我们可以求出两个东西:
    一个叫 rank[i], (S_i)在所有后缀中的排名
    一个叫 sa[i] , 指排名为i的后缀的是(S_{sa[i]})

    后缀数组怎么求

    我们可以考虑使用倍增的思想求解

    利用字符串字典序的特性 (先比较高位再比较低位)

    具体来说, 求解时先求出当前长度 len 时的答案
    即: 每个 S[i...min(i+len-1,n)] 的排名与位置的双射
    然后递推出长度为 (2*len) 时的情况
    比较过程可用基数排序实现

    精华代码

    void SA()
    {
        int m=300; //可能出现的排名数量
        for(re int i=1;i<=n;++i) cnt[rk[i]=s[i]]++; //先把长度为1的子串算出答案
        for(re int i=1;i<=m;++i) cnt[i]+=cnt[i-1];
        for(re int i=n;i>=1;--i) sa[cnt[rk[i]]--]=i;
        for(re int w=1;;w<<=1)
        {
            int p=0;
            for(re int i=n;i>n-w;i--) id[++p]=i; //基数排序
            for(re int i=1;i<=n;++i) if(sa[i]>w) id[++p]=sa[i]-w;
            for(re int i=1;i<=m;++i) cnt[i]=0;
            for(re int i=1;i<=n;++i) cnt[rk[id[i]]]++;
            for(re int i=1;i<=m;++i) cnt[i]+=cnt[i-1];
            for(re int i=n;i>=1;--i) sa[cnt[rk[id[i]]]--]=id[i];
            p=0; memcpy(od, rk, sizeof(rk)); 
            for(re int i=1;i<=n;++i) rk[sa[i]]=cmp(sa[i],sa[i-1],w) ? p : ++p; //利用sa推出rk
            if(p==n) break; m=p;
        }
    }
    

    height数组

    总概

    height[i]表示排名第i名的子串与前一名子串的LCP的长度

    以下用ht代表height

    有了ht数组, 本质上我们得到的是所有后缀的前缀的信息, 而后缀的前缀,就是S中的子串
    所以我们可以进行很多问题的处理

    求解ht(代码)

    先引入一个结论: (ht[rk[i]]>=ht[rk[i-1]]]-1)
    证明可参考oiwiki

    for(re int i=1,j=0;i<=n;++i)
    {
        if(j) j--;
        while(s[i+j]==s[sa[rk[i]-1]+j])++j;
        ht[rk[i]]=j;
    }
    

    应用

    子串的LCP

    由定义可知,求给定两个子串的LCP,直接找到以它们为起始位置的后缀,对ht求区间min即可

    求不同子串的数目

    正难则反,考虑总数减掉重复的子串数目
    那么重复的子串,就可以理解成重复的后缀的前缀,也就是排序后每个后缀与上一个的LCP
    (ans=n*(n+1)/2-sum_{i=2}^nht[i])

    求两个串(不同/相同)子串数目

    先将两个串拼一起,算出长串的答案,再减去两个串各自内部的答案

    才会这些,慢慢更吧...

    小技巧

    求解两个串有关题目

    将B串拼在A串后,中间插入一个字符集以外的字符间隔

    嗯,就这样了...
  • 相关阅读:
    Hit Event 击中碰撞
    基于ReentrantLock通知唤醒的生产消费模式
    spring 源码构建
    读写分离、分库、分表
    python 反射的使用
    基础算法
    git 命令使用
    java设计模式应用
    linux 中python的使用
    linux命令
  • 原文地址:https://www.cnblogs.com/yzhx/p/15252958.html
Copyright © 2011-2022 走看看