倍增算法,时间复杂度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的更多相关文章

  1. 后缀数组(suffix array)

    参考: Suffix array - Wiki 后缀数组(suffix array)详解 6.3   Suffix Arrays - 算法红宝书 Suffix Array 后缀数组 基本概念 应用:字 ...

  2. 后缀数组(suffix array)详解

    写在前面 在字符串处理当中,后缀树和后缀数组都是非常有力的工具. 其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料. 其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现, ...

  3. 利用后缀数组(suffix array)求最长公共子串(longest common substring)

    摘要:本文讨论了最长公共子串的的相关算法的时间复杂度,然后在后缀数组的基础上提出了一个时间复杂度为o(n^2*logn),空间复杂度为o(n)的算法.该算法虽然不及动态规划和后缀树算法的复杂度低,但其 ...

  4. 数据结构之后缀数组suffix array

    在字符串处理当中,后缀树和后缀数组都是非常有力的工具,其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料.其实后缀是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多 ...

  5. 后缀数组 (Suffix Array) 学习笔记

    \(\\\) 定义 介绍一些写法和数组的含义,首先要知道 字典序 . \(len\):字符串长度 \(s\):字符串数组,我们的字符串存储在 \(s[0]...s[len-1]\) 中. \(suff ...

  6. 【模板】BZOJ 1692:队列变换—后缀数组 Suffix Array

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1692 题意: 给出一个长度为N的字符串,每次可以从串头或串尾取一个字符,添加到新串中,使新串 ...

  7. 笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)

    议题:后缀数组(Suffix Array) 分析: 后缀树和后缀数组都是处理字符串的有效工具,前者较为常见,但后者更容易编程实现,空间耗用更少:后缀数组可用于解决最长公共子串问题,多模式匹配问题,最长 ...

  8. suffix array后缀数组

    倍增算法 基本定义子串:字符串 S 的子串 r[i..j],i≤j,表示 r 串中从 i 到 j 这一段也就是顺次排列 r[i],r[i+1],...,r[j]形成的字符串. 后缀:后缀是指从某个位置 ...

  9. Suffix Array 后缀数组

    后缀数组 顾名思义.SuffixArray(下面有时简称SA) 和字符串的后缀有关. 后缀:字符串中某个位置一直到结尾的子串.(SA中讨论包含了原串和空串).所以共同拥有len+1个后缀. 后缀数组: ...

随机推荐

  1. web模拟telnet

    https://blog.csdn.net/midion9/article/details/51781402 https://blog.csdn.net/hackstoic/article/detai ...

  2. Android Studio查看类中所有方法和属性

    ctrl+f3效果: alt+7效果: 注意区别:虽然所有方法都有,但是顺序自己一看效果便知.一个是根据类中的顺序,另一个是根据a-z的开头字母顺序. 百度查了一下快捷键是ctrl+f12.但是自己试 ...

  3. HDU 2087 剪花布条【在字符串中不可重叠地寻找子串数量】

    一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?  Input输入中含有一些数据,分别是成对出现的花布条和 ...

  4. JavaScript防止重复提交表单

    往往有些用户网络慢或者其他问题,在提交表单的时候使劲点击保存提交按钮,在提交表单的时候加上下面的代码,即可以限制在一定时间内,只有一次点击是有效的. <script> var mypret ...

  5. Proxy(2016山东省省赛C)(最短路)(spfa)

    问题 C: Proxy 时间限制: 2 Sec  内存限制: 128 MB提交: 17  解决: 5[提交][状态][讨论版] 题目描述 Because of the GFW (Great Firew ...

  6. POJ 3608 Bridge Across Islands (旋转卡壳)

    [题目链接] http://poj.org/problem?id=3608 [题目大意] 求出两个凸包之间的最短距离 [题解] 我们先找到一个凸包的上顶点和一个凸包的下定点,以这两个点为起点向下一个点 ...

  7. 10.2(java学习笔记)JDBC事务简述

    一.事务 事务是指作为一系列操作组成的一个整体,该整体只有两种状态,要么全部执行,要么全部不执行. 当组成这个事务的所有语句都执行成功则该事务执行,只要有一条语句执行失败则该事务不执行. 假设这里有一 ...

  8. Java多线程——ReentrantLock源码阅读

    上一章<AQS源码阅读>讲了AQS框架,这次讲讲它的应用类(注意不是子类实现,待会细讲). ReentrantLock,顾名思义重入锁,但什么是重入,这个锁到底是怎样的,我们来看看类的注解 ...

  9. map泛型 map不指定泛型 与 Map<Object,Object>的区别

    map泛型 map不指定泛型 与 Map<Object,Object>的区别 private void viewDetail(){ Map map1 = new HashMap(); Ma ...

  10. 修复XAMPP安装过程中 因端口80被占用 Apache无法启动的问题

    Fix XAMPP Apache Not Starting Because Port 80 In Use XAMPP中Apache服务器无法启动,出现该问题的最常见原因是由于默认端口号80可能已被其他 ...