热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

算法模板——后缀数组

后缀数组是什么?可以吃吗?不可以吃,它是给一个字符串的所有后缀进行排序的算法。如:一个字符串aabaaaab,

后缀数组是什么?可以吃吗?
不可以吃,它是给一个字符串的所有后缀进行排序的算法。
如:一个字符串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&#61;100000;char s[(maxn<<1)&#43;10];
int sa[(maxn<<1)&#43;10],rank[(maxn<<1)&#43;10],tmp[(maxn<<1)&#43;10];
int sum[(maxn<<1)&#43;10],a[(maxn<<1)&#43;10],n;inline int swap(int *&x,int *&y)//指针swap
{int *t&#61;x;x&#61;y;y&#61;t;return 0;
}inline int suffix_sort()
{int *x&#61;rank,*y&#61;tmp,m&#61;26;//先排序for(register int i&#61;1; i<&#61;n; &#43;&#43;i){x[i]&#61;a[i];y[i]&#61;i;&#43;&#43;sum[x[i]];}for(register int i&#61;1; i<&#61;m; &#43;&#43;i){sum[i]&#43;&#61;sum[i-1];}for(register int i&#61;n; i; --i){sa[sum[x[i]]]&#61;i;--sum[x[i]];}int len&#61;1,p&#61;1;while(p0;//每次循环设一下初值&#xff0c;然后排序for(register int i&#61;n-len&#43;1; i<&#61;n; &#43;&#43;i){&#43;&#43;p;y[p]&#61;i;}for(register int i&#61;1; i<&#61;n; &#43;&#43;i){if(sa[i]-len>0){&#43;&#43;p;y[p]&#61;sa[i]-len;}}//前面是按第二关键字排序&#xff0c;接下来按第一关键字排序for(register int i&#61;0; i<&#61;m; &#43;&#43;i){sum[i]&#61;0;}for(register int i&#61;1; i<&#61;n; &#43;&#43;i){&#43;&#43;sum[x[y[i]]];}for(register int i&#61;1; i<&#61;m; &#43;&#43;i){sum[i]&#43;&#61;sum[i-1];}for(register int i&#61;n; i; --i){sa[sum[x[y[i]]]]&#61;y[i];--sum[x[y[i]]];}swap(x,y);//现在y数组已经没有用了p&#61;1;x[sa[1]]&#61;1;//下一个步骤是去重for(register int i&#61;2; i<&#61;n; &#43;&#43;i){if(!((y[sa[i-1]]&#61;&#61;y[sa[i]])&&(y[sa[i-1]&#43;len]&#61;&#61;y[sa[i]&#43;len]))){&#43;&#43;p;}x[sa[i]]&#61;p;}len<<&#61;1;}//如果所有的都已经排好序&#xff0c;那么就没有必要排下去了&#xff0c;退出p&#61;0;//在上面计算的步骤中x数组记录的值可能不是真正的rank数组&#xff0c;需要重新计算for(register int i&#61;1; i<&#61;n; &#43;&#43;i){&#43;&#43;p;rank[sa[i]]&#61;p;}return 0;
}int main()
{scanf("%s",s&#43;1);n&#61;strlen(s&#43;1);for(register int i&#61;1; i<&#61;n; &#43;&#43;i){a[i]&#61;s[i]-&#39;a&#39;&#43;1;}suffix_sort();for(register int i&#61;1; i<&#61;n; &#43;&#43;i){printf("%d\n",sa[i]);}return 0;
}

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



推荐阅读
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
author-avatar
手机用户2502937657
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有