首页 > 其他分享 >后缀数组学习笔记

后缀数组学习笔记

时间:2023-05-04 18:33:59浏览次数:31  
标签:le lcp 后缀 笔记 int 数组 sa rk

概念

后缀数组,即对于一个串,它的每个后缀按字典序排序后得到的数组。

有两个数组要求:

  1. \(SA_i\):排名为 \(i\) 的后缀的开头位置
  2. \(RK_i\):以 \(i\) 为开头的后缀的排名

朴素

sort排序一下

优化

倍增优化:我们进行 \(\log n\) 次排序,第 \(k\) 次取所有后缀的前 \(2^k\) 个字符进行排序。若上次排序第 \(i\) 为开头的后缀排名为 \(rkl_i\)(可并列),那假如这次需要比较以 \(i\) 开头的串与以 \(j\) 开头的串,只需要先比较 \(rkl_i\) 与 \(rkl_j\),若相等再比较 \(rkl_i+2^{k-1}\) 与 \(rkl_j+2^{k-1}\) 即可。显然这样是正确的。

#include<iostream> 
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
string a;
int sa[1000005],rk[1000005],tmp[1000005];
int k;
inline bool cmp(int x,int y)
{
    if(rk[x]==rk[y]) //前2^(k-1)相等,比较后k个 
    {
        int i=(x+k<=a.size()?rk[x+k]:-1); //防止越界 
        int j=(y+k<=a.size()?rk[y+k]:-1);
        return i<j;
    }
    return rk[x]<rk[y];
}
void GetSark()
{
    for(int i=0;i<=a.size();i++) //初始化 
    {
        sa[i]=i;
        rk[i]=(i<a.size()?a[i]+1:0);
    }
    for(int i=1;i<=a.size();i=i*2)
    {
        k=i;
        sort(sa,sa+a.size()+1,cmp); //基排懒了 
        tmp[sa[0]]=0; //暂存rk 
        for(int z=1;z<=a.size();z++)
        {
            tmp[sa[z]]=tmp[sa[z-1]]+(cmp(sa[z-1],sa[z])?1:0); //如果比上一个大,排名就增加 
        }
        for(int z=0;z<=a.size();z++)
        {
            rk[z]=tmp[z]; //复制 
        }
    }
}
signed main()
{
    cin>>a;
    GetSark();
    for(int i=a.size();i>=1;i--) //注意,最后有空串 
    {
    	sa[i]++;
    	rk[i]=rk[i-1];
    }
    for(int i=1;i<=a.size();i++)
    {
		cout<<sa[i]<<' '<<rk[i]<<endl;
	}
} 

应用

在字符串 \(S\) 中找字符串 \(T\)

二分排名即可

bool find(string S,string T)
{
    int l=0,r=S.size(),ans;
    while(l<=r)
    {
    	int mid=r+l>>1;
        if(S.compare(sa[mid],T.size(),T)==-1)
        {
            l=mid+1;
        }
        else
        {
        	ans=mid;
            r=mid-1;
        }
    }
    return S.compare(sa[ans],T.size(),T)==0;
}

LCP

LCP即最长公共前缀

SA排完序后,有:

  1. \(lcp(i,j)=\min(lcp(i,k),lcp(k,j))(1 \le i \le k \le j)\)
  2. \(lcp(i,j)=\min(lcp(k,k-1))(1 \le i < k \le j)\)

height

后缀数组的另一应用

\(height_i\) 表示 \(lcp(sa_i,sa_{i-1})\),即排名相邻的两个后缀的最长公共前缀的长度。求 \(lcp(i,j)\) 直接RMQ即可。

对于 \(i>1\) 且 \(RK_i>1\),一定有 \(h_i≥h_{i-1}-1\)

则 \(O(n)\) 扫一扫就可以了

void get_height()
{
    int k=0;
    for(int i=1;i<=a.size();i++)
    {
        if(k)
        {
            k--;
        }
		int j=sa[rk[i]-1];
        while(a[i+k]==a[j+k]) k++;
        height[rk[i]]=k;
    }
}

标签:le,lcp,后缀,笔记,int,数组,sa,rk
From: https://www.cnblogs.com/lizhous/p/17372177.html

相关文章

  • 点分治学习笔记
    概念点分治用于解决有一定要求的链的计数。对于点\(u\)的子树的问题,可以将答案分为:经过点\(u\)不经过点\(u\)第一种可以用桶加暴力。枚举一端的长度,用桶计算另一端长度;第二种分到子树中解决即可。注意到,在随机选根的时候该算法表现不优秀,但若根为重心,因为每次子树......
  • 网络流学习笔记
    概念最大流:在一个网络图上,每个边有流量限制,假如起始点有无线流量,求最多能有多少流量流到终点。增广路:一条从起始点到终点了路径,可以流流量。算法Ford-Fulkerson算法解决这个问题,可以用Ford-Fulkerson算法。该算法的核心就是寻找增广路。每找到一条增广路,就给它它能承受......
  • 实例 042 获取一维数组最小值
      你可以使用以下代码来获取一维数组中的最小值:int[]arr={5,3,9,1,7};intmin=arr[0];for(inti=1;i<arr.length;i++){if(arr[i]<min){min=arr[i];}}System.out.println("最小值为:"+min);  在上面的代码中,我们首先初始......
  • C语言函数指针数组,GCC编译问题
    使用C语言函数指针数组实现简单的计算器,代码如下#include<stdio.h>#include<stdlib.h>doubleadd(doublea,doubleb){return(a+b);};doublesub(doublea,doubleb){return(a-b);};doublemul(doublea,doubleb){return(a*b);};doubl......
  • C++用return{}来返回空的Vector数组
    本人在刷Leecode题目的时候发现以下代码classSolution{public:std::unordered_map<int,int>map;for(inti=0;i<nums.size();i++){//遍历当前元素,并在map中寻找是否有匹配的keyautoiter=map.find(target-nums[i]......
  • LeetCode 双周赛 103(2023/04/29)区间求和的树状数组经典应用
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。大家好,我是小彭。这场周赛是LeetCode双周赛第103场,难得在五一假期第一天打周赛的人数也没有少太多。这场比赛前3题比较简单,我们把篇幅留给最后一题。往期周赛回顾:LeetCode单周赛第342场·容......
  • Java 数组、List初始化赋值
    1数组初始化赋值//第一种初始化赋值方式String[]strs1={"1","2"};//第二种初始化赋值方式String[]strs2=newString[]{"1","2"};2List初始化赋值//第一种初始化赋值方式List<String>strList1=Arrays.asList(newString[]{"1","2"});......
  • TypeScript 学习笔记 — 模板字符串和类型体操(十五)
    目录基本介绍字符串类型体操实操环节1.字符串首字母大写CapitalizeString2.获取字符串第一个字符FirstChar3.获取字符串最后一个字符LastChar4.字符串转元组StringToTuple5.元组转字符串TupleToString6.重复字符串RepeatString7.字符串分割SplitString8.获取字符串......
  • react.js学习笔记
    (1)      参考文献1.前端技术手册2.在线编码......
  • POJ 3321 Apple Tree(树状数组)
    AppleTreeTimeLimit: 2000MS MemoryLimit: 65536KTotalSubmissions: 21635 Accepted: 6573DescriptionThereisanappletreeoutsideofkaka'shouse.Everyautumn,alotofappleswillgrowinthetree.Kakalikesappleverymuch,sohehasbeen......