首页 > 其他分享 >后缀数组

后缀数组

时间:2023-07-13 21:35:10浏览次数:32  
标签:LCP 后缀 Height 数组 排名 sa rk

构造后缀数组

我们会得到两个数组 \(sa_i\) 表示排名为 \(i\) 的后缀是哪一个,\(rk_i\) 表示后缀 \(i\) 的排名。

这里只讲倍增做法。

原理非常简单,如下图:

实现需要一个对两位关键字进行排序的基数排序,设 \(y_i\) 表示按照第二维关键字排序,排名为 \(i\) 的是哪一个位置。设 \(rk_i\) 表示第 \(i\) 个位置,第一维关键字排序,排名是多少。

我们按照 \(i\) 从小到大把 \(rk_{y_i}\) 加入我们的桶中(我们用桶排来实现),对桶做前缀和之后,从大到小枚举 \(n\),按照 \(rk_{y_i}\) 来重新计算每个位置的排名。

这样做正确性显然,考虑如果两个位置第二维关键字排名不同,而第一维相同,那么排名越大的会先被枚举到,导致排名变大。如果第一维就不同,那么第一维更优的显然会排名更小。

所以就可以简单构造了,具体代码请到代码仓库。

求 height

LCP 的定义是最长公共前缀,以下用 \(LCP(i,j)\) 表示编号为 \(i\) 的后缀和编号为 \(j\) 的后缀的 LCP,我们令 \(Height_i=LCP(sa_i,sa_{i-1})\),而 \(Height_1\) 可以视作 \(0\)。我们考虑如何求 \(Height\) 数组。

  • 引理:\(Height_{rk_i}\ge Height_{rk_{i-1}}-1\)。

证明:如果 \(Height_{rk_{i-1}-1}\) 小于等于 \(1\),那么上面这个式子显然成立,这是因为 \(Height_i\ge 0\)。

如果 \(Height_{rk_{i-1}-1}>1\),我们考虑设后缀 \(i-1\) 为 \(aAD\),那么后缀 \(i\) 就是 \(AD\),其中 \(A\) 是一个长度为 \(Height_{rk_{i-1}}-1\) 的字符串,由于 \(Height\) 数组的定义,我们考虑后缀 \(sa_{rk_{i-1}-1}\) 这个字符串一定是 \(aAB\) 的形式,所以 \(sa_{rk_{i-1}-1}+1\) 这个后缀一定是 \(AB\) 的形式,所以这个后缀一定排在后缀 \(i\) 的前面,所以我们可以知道 \(Height_{rk_i-1}\) 一定包含字符串 \(A\),所以结论成立。

我们利用上面这个东西就可以 \(O(n)\) 的来求 \(Height\) 数组了。

有一个结论是 \(LCP(sa_i,sa_j)=\min_{i+1\le k\le j}Height_k\),这个可以感性理解一下,如果 \(Height\) 一直大于某个值,那么这一段就一直有,反之,肯定是在一个后缀中改变。

标签:LCP,后缀,Height,数组,排名,sa,rk
From: https://www.cnblogs.com/HeNuclearReactor/p/17552212.html

相关文章

  • 循环结构,相关操作字符的库函数,数组
    一,三大循环语句1.while循环当你不知道循环次数时,可以使用while循环#include<stdio.h>intmain(){ inti=123; intj=0; while(i!=j) { scanf("%d",&j); } printf("匹配成功\n"); return0;}以上代码的循环判断条件是i!=j当条件一直成立时,它就会一......
  • Java如何将数组转换为集合?
    在Java中,可以使用`Arrays`类的`asList()`方法将数组转换为集合。该方法接受一个数组作为参数,并返回一个包含数组元素的固定大小的列表。以下是将数组转换为集合的示例:String[]array={"item1","item2","item3"};List<String>list=Arrays.asList(array);在上述示例中,......
  • JavaScript 中获取数组最后一个元素3种方法及性能
    当需要从JavaScript中的数组中获取最后一个元素时,有多种选择,本文将提供3种可用方法。1.数组length属性length属性返回数组中元素的数量。从数组的长度中减去1得到数组最后一个元素的索引,使用它可以访问最后一个元素。从长度中减去1的原因是,在JavaScript中,数组索引......
  • 求js数组最大值
    1letarr=[1,2,3,4,5]23letmax=arr.reduce((prev,cur)=>{4returnMath.max(prev,cur)5})67console.log(max)//expectedoutput:5 //找出数组中最大/小的数字constnumbers=[5,6,2,3,7];//使用Math.min/Math.max以及apply函数......
  • JS去除对象数组中指定字段为空的数据
     去掉为空字段constfilteredArr=this.arouselList.filter((obj)=>{                return!(Object.prototype.hasOwnProperty.call(obj,'pic')&&(obj.pic===null||obj.pic===undefined));               });去掉不......
  • 直接“printf”到char数组字符串——C语言snprintf函数
    注:我写这个只是为了备注并介绍一下这个神器。有关它的更详细用法,互联网的各个角落都不缺少资料。如果您和曾经的我一样是C语言的初学者,您有可能时常遇到那些“奇异”的字符串处理问题,例如,int里的数转成char数组字符串类型,在char数组中间插入或者删除什么东西,等等。要是采用传统方......
  • TypeScript系列 4.数组类型
    本系列知识部分基于小满ZS的TypeScript系列教程。我也会补充一些视频没有的内容。数组类型1.基本类型letarr:number[]=[1,2,3];letarr1:boolean[]=[true,true,false];//使用泛型letarr2:Array<boolean>=[true,true,false];2.对象类型interface......
  • 线段树模板 洛谷P3374 【模板】树状数组 1
    题目传送门题目描述如题,已知一个数列,你需要进行下面两种操作:1.将某一个数加上x2.求出某区间每一个数的和输入格式第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。接下来M行每行包含3......
  • 分块数组
    给定一个数组 arr 和一个块大小 size ,返回一个分块 的数组。分块 的数组包含了 arr 中的原始元素,但是每个子数组的长度都是 size 。如果 arr.length 不能被 size 整除,那么最后一个子数组的长度可能小于 size 。你可以假设该数组是 JSON.parse 的输出结果。换......
  • 不确定大小的数组怎么办?Java中三种常用的方法
    Java中如何操作不确定大小的数组1. 前言 1.1 什么是数组数组是一种存储多个相同类型数据的有序集合,它可以通过索引来访问每个元素。数组是一种引用类型的变量,它在内存中占用一块连续的空间。 1.2  数组的特点数组有以下几个特点:-数组的长度是确定的,一旦创建就不能......