学习笔记:后缀数组

后缀数组是指对于后缀排序后,每个后缀的位置:sa[rank]=pos:排名为rank的后缀是pos->len这个后缀

note:rank[pos]=rank:位置为pos的串排名为rank

白书上的代码简洁明了,很容易理解。

核心思想:我们对于每个位置开始的后缀,不直接计算,先计算从这个位置开始,向后1位是第几小,然后向后2位,向后4位,一直到*2>n,这时就算好了后缀数组

复杂度:O(n*log(n)^2) :倍增log(n),快排log(n)

代码:

bool cp(int x,int y){    //rank(2*k)[x]和rank(2*k)[y]可以由rank(k)[x],rank(k)[x+k]和rank(k)[y],rank(k)[y+k]比较得出     if(rank[x]!=rank[y]) return rank[x]<rank[y];    int rx=x+k<=n?rank[x+k]:-1;//当前位置是x,向后k位超出了长度,那么很明显,rank[x+k]是不存在的,也可以看做一个空串,rank=-1     int ry=y+k<=n?rank[y+k]:-1;    return rx<ry;}void sa(string s){    //******排名:第几小     n=s.length();    for(int i=0;i<=n;i++)    {        sa[i]=i; rank[i]=i<n?s[i]:-1;    }    for(k=1;k<=n;k*=2)    {        sort(sa,sa+n+1,cp);//sa排序,sa存的是每个排名的位置,也就是每个排名对应的串         //sa[0]即为排名为0的串对应的位置         temp[sa[0]]=0;//第一个rank为0         for(int i=1;i<=n;i++)        {            temp[sa[i]]=temp[sa[i-1]]+(cp(sa[i-1],sa[i]));//计算名次,因为sa已经排好序,这里计算如果两个串相等,那么排名一样,否则排名+1         }        for(int i=0;i<=n;i++)        {            rank[i]=temp[i];//直接赋值,上面那个因为是按sa排序,所以按sa赋值         }    }}
时间: 2024-08-01 17:58:08

学习笔记:后缀数组的相关文章

学习笔记----后缀数组

学习资料:IOI2009国家集训队论文--<后缀数组> 论文里面写的比较清晰了,但是代码里面没有解释,又从网上找到了一份代码的注释,解释的挺好的 地址:http://www.cnblogs.com/Lyush/p/3233573.html 这里是代码模板: 倍增算法实现的,效率很高. const int maxn = 10010; int wa[maxn], wb[maxn], wv[maxn], ws1[maxn]; int cmp(int *r, int a, int b, int l)

C和指针 学习笔记-3.数组与指针

数据名代表首地址 指向数组的指针 #include <stdio.h> extern void iterate(int *p); void main(){ int a[]={1,2,3,4,5}; iterate(a); } void iterate(int *p){ int i; for(i=0;i<5;i++){ printf("%d",*p++); } } 指向一维数组的指针 int (*p)[3] #include <stdio.h> void i

Swift学习笔记(12)--数组和字典的复制

Swift中,数组Array和字典Dictionary是用结构来实现的,但是数组与字典和其它结构在进行赋值或者作为参数传递给函数的时候有一些不同. 并且数组和字典的这些操作,又与Foundation中的NSArray和NSDictionary不同,它们是用类来实现的. 注意:下面的小节将会介绍数组,字典,字符串等的复制操作.这些复制操作看起来都已经发生,但是Swift只会在确实需要复制的时候才会完整复制,从而达到最优的性能. 字典的赋值和复制操作 每次将一个字典Dictionary类型赋值给一个

Swift学习笔记(5)--数组

数组的下标从0开始计数,相关方法属性涉及到下标时也从0开始计数 1.定义: //1.可变数组 var cityArray = ["Portland","San Francisco","Cupertino"] //2.不可变数组 let cityArray2 = ["Portland","San Francisco","Beijing"] //3.空数组 var animalArray =

JavaScript学习笔记:数组reduce()和reduceRight()方法

很多时候需要累加数组项的得到一个值(比如说求和).如果你碰到一个类似的问题,你想到的方法是什么呢?会不会和我一样,想到的就是使用for或while循环,对数组进行迭代,依次将他们的值加起来.比如: var arr = [1,2,3,4,5,6]; Array.prototype.sum = function (){ var sumResult = 0; for (var i = 0; i < this.length; i++) { sumResult += parseInt(this[i]);

【算法学习】后缀数组

一个字符串的题,有姿势水平的OIers的脑中应该要浮现出许多算法-- 但是我没有姿势,也没有水平,除了KMP和trie树,什么也想不起来. 直到我学了它--后缀数组! 多亏这玩意儿,我现在什么都想不起来了. 后缀数组干嘛用的? 主要处理同一个字符串中的重复子串问题. 如何实现? 注意到每一个子串,都是一个后缀的某个前缀,这个后缀和前缀都是唯一确定的. 而后缀相同的前缀,和他们的字典序有密切联系.你有没有想过,字典中的相邻单词,他们的公共前缀总是很长. 一个字符串的任意后缀,都能用它的起始位置的下

算法学习:后缀数组 height的求取

[定义] [LCP]全名最长公共前缀,两个后缀之间的最长前缀,以下我们定义 lcp ( i , j ) 的意义是后缀 i 和 j 的最长前缀 [z函数] 函数z [ i ] 表示的是,第 i 个后缀和字符串的最长前缀  [解决问题] 这两个算法都是在解决这个问题 即求后缀和字符串和后缀之间的最长公共前缀 但是有所不同的是, 后缀数组最终求出的是,字典序第 i 个后缀和第 i + 1 个后缀的最长公共前缀 z函数最终求出的是,第 i 个后缀和字符串的最长公共前缀 然后通过这个最长公共前缀求一些其他

es6学习笔记(2)数组(中)

接着上一篇,给大家再分享一些数组的其他方法.大家也可以去点击这里学习数组更多的方法 concat方法: 概述:    concat() 方法将传入的数组或非数组值与原数组合并,组成一个新的数组并返回. 参数: valueN:需要与原数组合并的数组或非数组值. 描述: concat 方法将创建一个新的数组,然后将调用它的对象(this 指向的对象)中的元素以及所有参数中的数组类型的参数中的元素以及非数组类型的参数本身按照顺序放入这个新数组,并返回该数组. concat方法并不修改调用它的对象(th

JavaScript新手学习笔记1——数组

今天,我复习了一下JavaScript的数组相关的知识,总结一下数组的API: 总共有11个API:按照学习的先后顺序来吧,分别是: ① toString()  语法:arr.toString(); 将数组转化为字符串,并且返回这个字符串,以逗号分隔:但是不改变原数组: 1 var arr=[1,2,3,4,5]; 2 var result=arr.toString(); 3 console.log(result); //1,2,3,4,5 4 console.log(arr); //[1,2,

数据结构学习笔记&mdash;&mdash;顺序数组1

线性表最简单的刚开始就是顺序存储结构,我是看着郝斌的视频一点一点来的,严蔚敏的书只有算法,没有具体实现,此笔记是具体的实现 为什么数据结构有ADT呢,就是为了满足数据结构的泛性,可以在多种数据类型使用 这里所说的数组并不是简单那种数组,这里所讲的是数组结构,就是在内存中是连续存储的,所以要先构造出一个这样的结构 typedef int ElemType; typedef struct { ElemType* elem; //数组结构中的数据区,可以是任何数据类型,常见的是结构体类型 int le