suffix array后缀数组

时间:2022-01-24 09:33:07

倍增算法

基本定义子串:字符串 S 的子串 r[i..j],i≤j,表示 r 串中从 i 到 j 这一段
也就是顺次排列 r[i],r[i+1],...,r[j]形成的字符串。

后缀:后缀是指从某个位置 i 开始到整个串末尾结束的一个特殊子串。

字串 r 的 从 第 i 个 字 符 开 始 的 后 缀 表 示 为 Suffix(i) , 也 就 是
Suffix(i)=r[i..len(r)]。

后缀数组:后缀数组 SA 是一个一维数组,它保存 1..n 的某个排列 SA[1],
SA[2],……,SA[n],并且保证 Suffix(SA[i]) < Suffix(SA[i+1]),1≤i<n。
也就是将 S 的 n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺

次放入 SA 中。

名次数组:名次数组 Rank[i]保存的是 Suffix(i)在所有后缀中从小到大排
列的“名次”。
简单的说,后缀数组是“排第几的是谁?”,名次数组是“你排第几?”。容
易看出,后缀数组和名次数组为互逆运算。如图 1 所示。

suffix array后缀数组

设字符串的长度为 n。为了方便比较大小,可以在字符串后面添加一个字符,

这个字符没有在前面的字符中出现过,而且比前面的字符都要小。在求出名次数

组后,可以仅用 O(1)的时间比较任意两个后缀的大小。在求出后缀数组或名次
数组中的其中一个以后,便可以用 O(n)的时间求出另外一个。任意两个后缀如
果直接比较大小,最多需要比较字符 n 次,也就是说最迟在比较第 n 个字符时一
定能分出“胜负”。

1.2 倍增算法

倍增算法的主要思路是:用倍增的方法对每个字符开始的长度为 2k 的子字
符串进行排序,求出排名,即 rank 值。k 从 0 开始,每次加 1,当 2k 大于 n 以
后,每个字符开始的长度为 2k 的子字符串便相当于所有的后缀。并且这些子字
符串都一定已经比较出大小,即 rank 值中没有相同的值,那么此时的 rank 值就
是最后的结果。每一次排序都利用上次长度为 2k-1的字符串的 rank 值,那么长
度为 2k 的字符串就可以用两个长度为 2k-1的字符串的排名作为关键字表示,然
后进行基数排序,便得出了长度为 2k的字符串的 rank 值。以字符串“aabaaaab”
为例,整个过程如图 2 所示。其中 x、y 是表示长度为 2k的字符串的两个关键字

suffix array后缀数组

模板

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define rep(i,n) for(int i = 0;i < n; i++)
const int maxn = 200000+66;
int rk[maxn],sa[maxn],height[maxn],w[maxn],wa[maxn],res[maxn];
void getSa (int len,int up) {
int *k = rk,*id = height,*r = res, *cnt = wa;
rep(i,up) cnt[i] = 0;
rep(i,len) cnt[k[i] = w[i]]++;
rep(i,up) cnt[i+1] += cnt[i];
for(int i = len - 1; i >= 0; i--) {
sa[--cnt[k[i]]] = i;
}
int d = 1,p = 0;
while(p < len){
for(int i = len - d; i < len; i++)
id[p++] = i;
rep(i,len)
if(sa[i] >= d)
id[p++] = sa[i] - d;
rep(i,len) r[i] = k[id[i]];
rep(i,up) cnt[i] = 0;
rep(i,len) cnt[r[i]]++;
rep(i,up) cnt[i+1] += cnt[i];
for(int i = len - 1; i >= 0; i--) {
sa[--cnt[r[i]]] = id[i];
}
swap(k,r);
p = 0;
k[sa[0]] = p++;
rep(i,len-1) {
if(sa[i]+d < len && sa[i+1]+d <len &&r[sa[i]] == r[sa[i+1]]&& r[sa[i]+d] == r[sa[i+1]+d])
k[sa[i+1]] = p - 1;
else k[sa[i+1]] = p++;
}
if(p >= len) return ;
d *= 2,up = p, p = 0;
}
}
int ans=0;
void getHeight(int len) {
rep(i,len) rk[sa[i]] = i;
height[0] = 0;
for(int i = 0,p = 0; i < len - 1; i++) {
int j = sa[rk[i]-1];
while(i+p < len&& j+p < len&& w[i+p] == w[j+p]) {
p++;
}
height[rk[i]] = p;
p = max(0,p - 1);
}
}
int getSuffix(char s[]) {
int len = strlen(s),up = 0;
for(int i = 0; i < len; i++) {
w[i] = s[i];
up = max(up,w[i]);
}
w[len++] = 0;
getSa(len,up+1);
getHeight(len);
return len;
} int main()
{
char s1[maxn];
scanf("%s",s1); getSuffix(s1);
return 0;
}

suffix array后缀数组的更多相关文章

  1. Suffix Array 后缀数组

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

  2. bzoj 4319&colon; Suffix reconstruction 后缀数组&plus;构造

    题目大意 给定后缀数组sa,要求构造出满足sa数组的字符串.或输出无解\(n\leq 5*10^5\) 题解 我们按照字典序来考虑每个后缀 对于\(Suffix(sa[i])\)和\(Suffix(s ...

  3. BZOJ 4319&colon; cerc2008 Suffix reconstruction&lpar;后缀数组&rpar;

    题面 Description 话说练习后缀数组时,小C 刷遍 poj 后缀数组题, 各类字符串题闻之丧胆.就在准备对敌方武将发出连环杀时,对方一记无中生有,又一招顺 手牵羊,小C 程序中的原字符数组就 ...

  4. BZOJ&period;4319&period;&lbrack;cerc2008&rsqb;Suffix reconstruction&lpar;后缀数组 构造 贪心&rpar;

    题目链接 \(Description\) 给定SA数组,求满足SA[]的一个原字符串(每个字符为小写字母),无解输出-1. \(Solution\) 假设我们现在有suf(SA[j]),要构造suf( ...

  5. 后缀数组&lpar;suffix array&rpar;

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

  6. 后缀数组&lpar;suffix array&rpar;详解

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

  7. 利用后缀数组&lpar;suffix array&rpar;求最长公共子串&lpar;longest common substring&rpar;

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

  8. 笔试算法题(40):后缀数组 &amp&semi; 后缀树(Suffix Array &amp&semi; Suffix Tree)

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

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

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

随机推荐

  1. 采集数据和memchche的存储使用,分页展示

    <?phpheader('content-type:text/html;charset=utf-8');//实例化memcache$mem=new Memcache();//链接$mem-&gt ...

  2. java 事件监听 - 键盘

    java 事件监听 - 键盘 //事件监听 //键盘事件监听,写了一个小案例,按上下左右,改变圆形的位置,圆形可以移动 import java.awt.*; import javax.swing.*; ...

  3. 3&period;Android之单选按钮RadioGroup和复选框Checkbox学习

    单选按钮和复选框在实际中经常看到,今天就简单梳理下. 首先,我们在工具中拖进单选按钮RadioGroup和复选框Checkbox,如图: xml对应的源码: <?xml version=&quo ...

  4. PHP &sol; JavaScript &sol; jQuery 表单验证与处理总结: 第①部分 PHP 表单验证与处理

    PHP VERSION = 5.3.10 一.关于 $_REQUEST PHP 文档关于 $_REQUEST 的说明: 说明 默认情况下包含了 $_GET,$_POST 和 $_COOKIE 的数组. ...

  5. 2-3 tree使用

    The 2-3 tree is also a search tree like the binary search tree, but this tree tries to solve the pro ...

  6. 22&period; Generate Parentheses产生所有匹配括号的方案

    [抄题]: Given n pairs of parentheses, write a function to generate all combinations of well-formed par ...

  7. hyperledger fabric各类节点及其故障分析 摘自https&colon;&sol;&sol;www&period;cnblogs&period;com&sol;preminem&sol;p&sol;8729781&period;html

    hyperledger fabric各类节点及其故障分析   1.Client节点 client代表由最终用户操作的实体,它必须连接到某一个peer节点或者orderer节点上与区块链网络通信.客户端 ...

  8. sqlserver中创建链接服务器图解教程

    1.展开服务器对象-->链接服务器-->右击"新建链接服务器" 注意:必须以数据库管理员身份登录(通常也就是sa帐号)后,才可以创建"链接服务器" ...

  9. 理解Underscore中的uniq函数

    uniq函数,是Underscore中的一个数组去重函数,给它传递一个数组,它将会返回该数组的去重副本. 1 ES6版本去重 在ES6版本中,引入了一个新的数据结构——set,这是一种类似数组的数据结 ...

  10. nginx中使用perl模块

    转载自:http://www.netingcn.com/nginx-perl.html 如果对于一个绝大部分内容是静态的网站,只有极少数的地方需要动态显示,碰巧你又了解一点perl知识,那么nginx ...