博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法模板——后缀数组
阅读量:6364 次
发布时间:2019-06-23

本文共 2190 字,大约阅读时间需要 7 分钟。

后缀数组是什么?可以吃吗?

不可以吃,它是给一个字符串的所有后缀进行排序的算法。
如:一个字符串aabaaaab,它的后缀排好序后起始位置分别是:4 5 6 1 7 2 8 3
显然如果暴力去排序时间复杂度为O(n2),可以用倍增算法或DC3算法来解决,本文主要介绍倍增算法(我才不会告诉你其实是我不会DC3算法呢)。
接下来定义如下几个数组:

数组名 意义
sai 原串S拍好序后第i个后缀的开头位置(就是排第几的是谁)
ranki 开头为i的后缀的名次(就是谁排第几)

引用大佬图解:

大佬图解1
倍增法的主要内容?
每次对长度为2k的串进行排序时都可以利用两个连续的长为2k1的串排序的结果来进行排序,当2k>=n时,每个串都是以这个串的起点为起点的后缀。
再次引用大佬图解:
大佬图解2
这张图是什么意思呢?
就是:x和y分别作为第一关键字和第二关键字,进行排序,以这一次排序的结果作为下一次排序的参考。
怎么排序?
需要排序的范围不超过n,当然是选择计数排序(基数排序,桶排序)啊。
时间复杂度?
O(nlogn),如果不使用计数排序就是O(nlog2n)
代码
温馨提示:复制到记事本上并将tab键调成8格效果更佳

#include 
#include
const int maxn=100000;char s[(maxn<<1)+10];int sa[(maxn<<1)+10],rank[(maxn<<1)+10],tmp[(maxn<<1)+10];int sum[(maxn<<1)+10],a[(maxn<<1)+10],n;inline int swap(int *&x,int *&y)//指针swap{ int *t=x; x=y; y=t; return 0;}inline int suffix_sort(){ int *x=rank,*y=tmp,m=26; //先排序 for(register int i=1; i<=n; ++i) { x[i]=a[i]; y[i]=i; ++sum[x[i]]; } for(register int i=1; i<=m; ++i) { sum[i]+=sum[i-1]; } for(register int i=n; i; --i) { sa[sum[x[i]]]=i; --sum[x[i]]; } int len=1,p=1; while(p
0) { ++p; y[p]=sa[i]-len; } } //前面是按第二关键字排序,接下来按第一关键字排序 for(register int i=0; i<=m; ++i) { sum[i]=0; } for(register int i=1; i<=n; ++i) { ++sum[x[y[i]]]; } for(register int i=1; i<=m; ++i) { sum[i]+=sum[i-1]; } for(register int i=n; i; --i) { sa[sum[x[y[i]]]]=y[i]; --sum[x[y[i]]]; } swap(x,y); //现在y数组已经没有用了 p=1; x[sa[1]]=1; //下一个步骤是去重 for(register int i=2; i<=n; ++i) { if(!((y[sa[i-1]]==y[sa[i]])&&(y[sa[i-1]+len]==y[sa[i]+len]))) { ++p; } x[sa[i]]=p; } len<<=1; } //如果所有的都已经排好序,那么就没有必要排下去了,退出 p=0; //在上面计算的步骤中x数组记录的值可能不是真正的rank数组,需要重新计算 for(register int i=1; i<=n; ++i) { ++p; rank[sa[i]]=p; } return 0;}int main(){ scanf("%s",s+1); n=strlen(s+1); for(register int i=1; i<=n; ++i) { a[i]=s[i]-'a'+1; } suffix_sort(); for(register int i=1; i<=n; ++i) { printf("%d\n",sa[i]); } return 0;}

转载于:https://www.cnblogs.com/Canopus-wym/p/10376289.html

你可能感兴趣的文章
怎样将优酷网站下载的视频KUX转MP4格式
查看>>
MongoDB 分组统计
查看>>
二进制状态码
查看>>
Vue 中 CSS 动画原理
查看>>
关于 Promise 的 9 个提示
查看>>
算法复习
查看>>
安卓中高级开发面试知识点之——缓存
查看>>
Java的初始化顺序
查看>>
《css揭秘》读书笔记
查看>>
js 判断回文字符串
查看>>
shields小徽章是如何生成的?以及搭建自己的shield服务器
查看>>
猫头鹰的深夜翻译:spring事务管理
查看>>
记一次使用Spring REST Docs + travis + github自动生成API接口文档的操作步骤(下)...
查看>>
1、集合 2、Iterator迭代器 3、增强for循环 4、泛型
查看>>
关于/var/run/docker.sock
查看>>
SCrapy爬虫大战京东商城
查看>>
用 JavaScript 实现链表操作 - 11 Alternating Split
查看>>
Laravel优秀扩展包整理
查看>>
日志分析之识别真假蜘蛛与处理办法
查看>>
回顾小程序2018年三足鼎立历程,2019年BAT火力全开
查看>>