后缀数组suffix array
倍增算法,时间复杂度O(nlogn)
sa从小到大保存相对大小的下标
理解LSD,x数组,sa数组
char s[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn],n; void build_sa(int m)
{
//LSD基数排序
int *x=t,*y=t2;//x数组保存rank
//字串长度为1,即对每一个元素的大小排序
for(int i=0;i<m;++i) c[i]=0;//计数数组清空
for(int i=0;i<n;++i) c[x[i]=s[i]]++;//统计出现次数
for(int i=1;i<m;++i) c[i]+=c[i-1];//计算前缀和
for(int i=n-1;i>=0;--i) sa[--c[x[i]]]=i;//sa从小到大保存每一个元素的下标 for(int k=1;k<=n;k<<=1){//k为要排序的子串长 //排序第二keyword
int p=0; //y[]从小到大保存第二keyword的下标
for(int i=n-k;i<n;++i) y[p++]=i;//从第n-k位開始的字串,第二keyword为0
for(int i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
//仅仅有下标大于k的第sa[i]个字符串的rank才干作为下一行的第sa[i]-k个字符串的第二keyword //排序第一keyword
//x[y[i]]是引用第一keyword,依据LSD第二次排序要在第一次的基础上
for(int i=0;i<m;++i) c[i]=0;//计数数组清空
for(int i=0;i<n;++i) c[x[y[i]]]++;//统计rank出现次数
for(int i=1;i<m;++i) c[i]+=c[i-1];//求前缀和
for(int i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];//sa[]从小到大保存双keyword的下标 p=1;swap(x,y);x[sa[0]]=0;//交换x,y数组 x[]数组从0到n-1保存rank值(0到p)
for(int i=1;i<n;++i){
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k] ? p-1:p++;//注意p-1
//因为p是计数rank值不同的字符串的数量,因此双keyword同样的串视为一样的rank
} if(p>=n) break; //p个字符串的rank值都不同 ,p>=n时说明大小确立,以后即使倍增,sa也不会改变
m=p;//用来下次基数排序的最大值
}
}
————————————————————————————————————--————————
————————————————————————————————————————————
void build_sa()
{
int *x=t,*y=t2;
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<n;++i) c[x[i]=y[i]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=n-1;i>=0;--i) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k;i<n;++i) y[p++]=i;
for(int i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<n;++i) c[x[y[i]]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i]; int p=0;swap(x,y);x[sa[0]]=0;
for(int i=1;i<n;++i){
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k] p-1:p++;
}
if(p>=n) break;
m=p; }
}
int m;
int cmp_suffix(char *pattern,int p)
{
return strncmp(pattern,s+sa[p],m);
} int find(char *p)
{
m=strlen(p);
if(cmp_suffix(p,0)<0) return -1;
if(cmp_suffix(p,n-1)>0) return -1;
int l=0,r=n-1;
while(l<=r){
int mid=l+(r-l)/2;
int res=cmp_suffix(p,mid);
if(!res) return mid;
if(res>0) l=mid+1;
if(res<0) r=mid-1;
}
return -1;
} /*
设suffix(k)是排在suffix(i-1)前一名的后缀。则它们的最长公共前缀是h[i-1] 。那么suffix(k+1)将排在suffix(i)的前面(这里要求h[i-1]>1,假设h[i-1]≤ 1,原式显然成立)而且suffix(k+1)和suffix(i)的最长公共前缀是h[i-1]-1, 所以suffix(i)和在它前一名的后缀的最长公共前缀至少是h[i-1]-1。依照h[1] ,h[2],……,h[n]的顺序计算。并利用h数组的性质,时间复杂度能够降为O (n)。 */
void get_height()
{
for(int i=0;i<n;++i) rank[sa[i]]=i;
int k=0;
for(int i=0;i<n;++i){
if(k) k--;
int j=sa[rank[i]]-1;
while(s[j+k]==s[i+k]) k++;
height[rank[i]]=k;
}
}
后缀数组suffix array的更多相关文章
- 后缀数组(suffix array)
参考: Suffix array - Wiki 后缀数组(suffix array)详解 6.3 Suffix Arrays - 算法红宝书 Suffix Array 后缀数组 基本概念 应用:字 ...
- 后缀数组(suffix array)详解
写在前面 在字符串处理当中,后缀树和后缀数组都是非常有力的工具. 其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料. 其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现, ...
- 利用后缀数组(suffix array)求最长公共子串(longest common substring)
摘要:本文讨论了最长公共子串的的相关算法的时间复杂度,然后在后缀数组的基础上提出了一个时间复杂度为o(n^2*logn),空间复杂度为o(n)的算法.该算法虽然不及动态规划和后缀树算法的复杂度低,但其 ...
- 数据结构之后缀数组suffix array
在字符串处理当中,后缀树和后缀数组都是非常有力的工具,其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料.其实后缀是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多 ...
- 后缀数组 (Suffix Array) 学习笔记
\(\\\) 定义 介绍一些写法和数组的含义,首先要知道 字典序 . \(len\):字符串长度 \(s\):字符串数组,我们的字符串存储在 \(s[0]...s[len-1]\) 中. \(suff ...
- 【模板】BZOJ 1692:队列变换—后缀数组 Suffix Array
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1692 题意: 给出一个长度为N的字符串,每次可以从串头或串尾取一个字符,添加到新串中,使新串 ...
- 笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)
议题:后缀数组(Suffix Array) 分析: 后缀树和后缀数组都是处理字符串的有效工具,前者较为常见,但后者更容易编程实现,空间耗用更少:后缀数组可用于解决最长公共子串问题,多模式匹配问题,最长 ...
- suffix array后缀数组
倍增算法 基本定义子串:字符串 S 的子串 r[i..j],i≤j,表示 r 串中从 i 到 j 这一段也就是顺次排列 r[i],r[i+1],...,r[j]形成的字符串. 后缀:后缀是指从某个位置 ...
- Suffix Array 后缀数组
后缀数组 顾名思义.SuffixArray(下面有时简称SA) 和字符串的后缀有关. 后缀:字符串中某个位置一直到结尾的子串.(SA中讨论包含了原串和空串).所以共同拥有len+1个后缀. 后缀数组: ...
随机推荐
- 通过Eclipse生成可运行的jar包
本来转自http://www.cnblogs.com/lanxuezaipiao/p/3291641.html 我是个追新潮的人,早早用上了MyEclipse10.最近需要使用Fat jar来帮我对一 ...
- HDU3414 Tour Route(竞赛图寻找哈密顿回路)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3414 本文链接:http://www.cnblogs.com/Ash-ly/p/5459540.html ...
- NULL always return false
Any comparison with null is false - = and <>, >, <, and so on. You cannot use null in an ...
- 自动渗透测试工具集APT2
自动渗透测试工具集APT2 APT2是Kali Linux新增的一款自动渗透测试工具集.它可以进行NMAP扫描,也可以直接读取Nexpose.Nessus和NMAP的扫描结果,然后自动进行渗透测试 ...
- java中为什么要用多线程
我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread).线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可能和其他线程共享一些资源,比 ...
- BSGS与二次剩余
BSGS $Big\ Step\ Giant\ Step$,大步小步法,一种在$O(\sqrt{p})$内求解方程$a^x\equiv b (mod\ p)$的算法. 先考虑$p$为质数的情况. 令$ ...
- CodeForces - 981E Addition on Segments
考虑每个点i在什么情况下会成为最大值. 当选的区间子集是 包含i的区间的一个子集的时候,i肯定会是最大值. 所以我们就可以用这种方法得到所有点的可能的最大值是多少... 也就是说,最后的局面可以仅由一 ...
- centos7下解决python3和python2同时存在但是无法使用pip3的问题
一.首先,官网下载python3的所需版本. wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tgz 想下载到那个文件夹下就先进入到 ...
- 通信编码解码 c11 实现 [ lua 专用版]
#include <istream> #include <ostream> #include <iostream> #include <strstream&g ...
- Linux下CURL设置请求超时时间
使用CURL时,有两个超时时间:一个是连接超时时间,另一个是数据传输的最大允许时间. 连接超时时间用--connect-timeout参数来指定,数据传输的最大允许时间用-m参数来指定. 例如: cu ...