后缀数组

转一个后缀数组的简单总结:

无人久伴 提交于 2019-11-27 00:49:54
后缀数组就是将字符串所有后缀排序后的数组,设字符串为S,令后缀Suffix(i)表示S[i..len(S)]。用两个数组记录所有后缀的排序结果: Rank[i]记录Suffix(i)排序后的序号,即Suffix[i]在所有后缀中是第Rank[i]小的后缀 SA[i]记录第i位后缀的首字母位置,即Suffix[SA[i]]在所有后缀中是第i小的后缀 然后就是怎么快速求所有后缀的顺序了,其中的关键是如何减少两个后缀比较的复杂度 方法是倍增法,定义一个字符串的k-前缀为该字符串的前k个字符组成的串,关于在k-后缀上的定义Suffix(k,i)、SA[k,i]和Rank[k,i]类似于前,则有 若Rank[k,i]=Rank[k,j]且Rank[k,i+k]=Rank[k,j+k],则Suffix[2k,i]=Suffix[2k,j] 若Rank[k,i]=Rank[k,j]且Rank[k,i+k]<Rank[k,j+k],则Suffix[2k,i]<Suffix[2k,j] 若Rank[k,i]<Rank[k,j],则Suffix[2k,i]<Suffix[2k,j] 这样就能在常数时间内比较Suffix(2^k, i)之间的大小,从而对Suffix(2^k,i)时行排序,最后 当2^k>n时,Suffix(2^k, i)之间的大小即为所有后缀之间的大小 于是求出了所有后缀的排序

后缀数组总结

醉酒当歌 提交于 2019-11-27 00:48:47
2009-10-25 09:05 后缀数组是处理字符串的有力工具,后缀数组可以解决大多数后缀树解决的问题,由于它的实现要比后缀树简单,因此深受广大ACM爱好者的喜爱,当然还是有一些问题只有后缀树能解决的问题,等学习了后缀树再将其添上。后缀数组最常用的是求取最长公共前缀。 后缀suffix数组,suffix【i】表示从第i个字符开始的后缀; 后缀数组sa,保留1~n的某个排列,保证suffix【sa【i】】<suffix【sa【i】】,可以证明任何从不同位置开始的后缀不可能相等,这里不再证明。 名词数组:名词数组rank【i】保存的是suffix【i】在所有后缀中从小到大排列的名次。简单的说,后缀数组是“排第几的是谁?”,名次数组时“你排第几?”。容易看出,后缀数组和名次数组互为逆运算。 height数组,height【i】表示suffix【sa【i-1】】和suffix【sa【i】】的最长公共前缀,实际中往往应用最多的就是最长公共前缀,用其求取必要的东西。 后缀数组可以解决的问题: 一、单个字符串的问题: (1) 重复字串 例1:可重叠最长重复子串 给定一个字符串,求最长重复子串,这两个子串可以重叠。 算法:只要求出最大的height就可以了。 例2:不可重叠最长重复子串(pku 1743) 给定一个字符串,求最长重复子串,这两个子串不能重叠。 算法:二分答案,变成判定性问题

后缀数组模板(别看了,看不懂的)

放肆的年华 提交于 2019-11-27 00:33:50
#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <iostream> // #include <ctime> // #include <cmath> // #include <map> // #include <vector> // #include <set> #include <string> #define open_in(x) freopen(""#x".in","r",stdin) #define open_out(x) freopen(""#x".out","w",stdout) #define open_(x) freopen(""#x".in","w",stdout) #define open(x) open_in(x); open_out(x) #define mes(x, y) memset(x, y, sizeof(x)) #define mec(x, y) memcpy(x, y, sizeof(x)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; const int X = 200010;

算法学习:后缀数组(SA)

*爱你&永不变心* 提交于 2019-11-26 23:21:33
【参考博客】 https://xminh.github.io/2018/02/27/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84-%E6%9C%80%E8%AF%A6%E7%BB%86(maybe)%E8%AE%B2%E8%A7%A3.html 【定义】 【后缀】 从第i位到字符串结尾的子串 【解决问题】 从而解决 ...................在字符串中找子串 ...................比较子串关系 ...................查找不同子串的数目 一般来说都是解决 字符串和子串关系的问题 【算法学习】 后缀数组能够在 nlogn的时间复杂度内求取出以下数组 SA [] 储存,第 i 个数字表示的是字典序第 i 大的后缀是以 SA_i 开始的后缀 即 “ 排第几的是哪个后缀 ” rank [] 储存,从第i位开始的后缀的字典序排名是 i 即 “ 某个后缀排第几个 ” 对SA的求取,我们可以看作对所有的后缀进行排序 而这个排序显然如果直接莽的话肯定T,所以我们需要另外一种方法 这里使用 基数排序+倍增 的方法进行优化 将所有的后缀进行排序得到SA ,这是我们的 目的 基数排序,是对两个关键字的元素进行排序从而达到线性复杂度的方法 显然,在当两个后缀第一个字符相等的情况下,我们不可避免的去用第二个字符进行比较

字符串匹配

痴心易碎 提交于 2019-11-26 19:45:23
字符串匹配 BF算法(朴素模式匹配) 时间复杂度O(m*n),普通的模式匹配算法 BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符; 若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。 模板 输出s2在s1里出现的次数 我写的,两行获取两行字符,第二行的字符串在第一行的字符串匹配,看看有几个 #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=1e6+5; int main(){ char str[maxn]; gets(str); char s[maxn]; gets(s); int len1=strlen(str); int len2=strlen(s); int cnt=0; for(int i=0;i<len1;i++){ if(str[i]==s[0]){ int flag=1; for(int j=0;j<len2;j++){ if(str[i+j]==s[j]){ }else{ flag=0; break; } } if(flag)cnt++; } } printf("%d\n",cnt); return

poj3729【后缀数组】

自古美人都是妖i 提交于 2019-11-26 19:20:37
这题也是从白书上来的。 传送门:https://vjudge.net/problem/POJ-3729 题意:给你a、b串,让你求a串中有多少后缀与b串的所有后缀的公共前缀的长度最大值等于k。 借鉴:https://blog.csdn.net/lj94093/article/details/44703723 其实这题有几点要说的。 1、后缀数组常规做法,把两个串用一个特殊字符连起来,然后这题给的数可能为0,所以要手动+1,也不知道为什么值为0就不行。。。 2、与b的公共前缀长度最大值等于k转换成 num(最大值>=k)-num(最大值>=k+1)。这样转换有什么用呢?最大值>=k,也就是我a的后缀满足与一个b的后缀>=k就可统计了。 3、具体可见代码,看看代码就懂了。我们h数组中小于k的把h数组分成若干段,试想,在同一段中,h都是>=k的,那么如果我们在这一段中有一个b的串,那么这一段中所有的a串都是满足>=k的吧,因为有一个满足即可。 4、第3条分析只是大概的分析,还有点细节,而且这个细节做后缀数组的题经常遇到,就是h(其实就是网上的height数组)数组记录的含义,使得 i 与 j 的最大公共前缀长度是h[i+1] 到h[ j ]。也就是左开右闭。所以加入是 i 到 j这一段中 h 都大于等于k的话,我们还得看看 i-1 那一位的情况,尽管h[ i -1 ] <k

Sequence POJ - 3581 后缀数组

半城伤御伤魂 提交于 2019-11-26 18:22:29
题意: 将一个序列分成非空的三部分,将每部分翻转后组合成一个新的序列, 输出这样操作得到的序列中字典序最小的序列 (保证第一个数是数组中最大的元素) 题解: 把数组当作串串。 因为第一个数最大,所以我们可以先将串反过来,然后可以找第一个sa[ i ] > 1 , 因为sa[ i ] 就是字典序从小到大排列的。 然后第二部分的处理就我是看题解的。 第二部分不能直接这样求解 例如: 除去第一部分之后的序列为 4 3 2 2 ,如果直接选取字典序最小的的串是 2 ,那么最后的解是 2 4 3 2 显然是错的 但是我们将串翻倍后变为4 3 2 2 4 3 2 2 前4个数中字典序最小的就为2 2 4 3 2 2 ,然后出去翻倍的部分 4 3 2 2 这样的求解就是最优的了 剩下的直接补充即可。 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <iostream> 8 #include <map> 9 #include <stack> 10 #include <string> 11 #include <time.h> 12 #include <vector> 13 #define

kmp算法

人盡茶涼 提交于 2019-11-26 17:00:15
————————————————————时光点燃了少年的梦想....... 1. abcdef 的前缀:  a,   ab,   abc,   abcd,   abcde   (abcdef 可不是前缀哦!) abcdef 的后缀:  f,   ef,   def,   cdef,     bcdef,  (abcdef可不是后缀哦!) abcdef 的 前缀后缀最长公共元素长度 为  0         (因为其前缀与后缀没有相同的!) ababa的前缀:    a,  ab,  aba,  abab,   ababa的后缀:    a,  ba,  aba,  baba, ababa的 相同前缀后缀的最大长度 为:  3 ascesubluffy 的 prefix:      a,  as,  asc,  asce,  asces,  ascesu,  ascesub,  ascesubl,  ascesublu,  ascesubluf,  ascesubluff, asecesubluffy 的postfix:   y,  fy,   ffy,    uffy,  luffy,   bluffy,  ubluffy,   subluffy,   esubluffy,   cesubluffy,  scesubluffy, 长度为 len 的字符串的前缀与后缀的个数为 2*

模板积累——后缀数组(最长公共子串、回文、子串个数)

我怕爱的太早我们不能终老 提交于 2019-11-26 16:45:57
#include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1000+7; char s[maxn]; int sa[maxn], t[maxn], t2[maxn], c[maxn], rk[maxn], height[maxn]; void build_sa(int m, int n) { //n为字符串的长度,字符集的值为0~m-1 n++; 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] = s[i]]++; for (int i = 1; i < m; i++) c[i] += c[i - 1]; for (int i = n - 1; ~i; i--) sa[--c[x[i]]] = i; for (int k = 1; k <= n; k <<= 1) { //直接利用sa数组排序第二关键字 int p = 0; for (int i = n - k; i < n; i++) y[p+

【模板】后缀数组

自古美人都是妖i 提交于 2019-11-26 16:26:29
致谢jdr和ldl学长$qwq$ 后缀数组,顾名思义,就是对于一个字符串的每一个后缀的数组。 比如对于字符串fatcat,其所有后缀如下: fatcat atcat tcat cat at t 其按照字典序排序结果如下: at atcat cat fatcat t tcat 一般来说,对于每个后缀,要求的数组有3个: rank[]:字符串中以第i位开始的后缀的排名 sa[]:排名为i的后缀开始的那一位的下标,和rank互为逆映射(sa[rank[i]] = i,反之亦然) height[]: 排名为i和i-1的后缀的LCP(最长公共前缀)长度(显然排名邻近的后缀最长公共前缀较长) 后缀数组有用的部分是height[],核心是求sa[]。 求sa[]需要用到倍增法。 假设已经求出长度为k的字符串排序后的数组,可以通过合并求出长度为2k的。 单次排序复杂度为O(N),每次长度扩大一倍,共需扩大logN次。总的时间复杂度为O(NlogN) 每次合并i和i+2^k(k=0~…)。比如上图中第二次,3代表(1,2),5代表(3,4),35就代表(1,2,3,4)。 桶排序(bucket sort)是怎么排的? 因为我喜欢buck,所以把桶叫做buck[] 类似计数排序,首先要知道每种数有几个。 然后用前缀和的方式,比如1,1,4,5,1,4, 先枚举每一位,相应的buck[s[i]]++