void Suffix_Array(char*a,int n,int m=){
//变量含义:m是字符集大小,n是字符串长度,c是一个桶数组,a[i]是字符串(下标从1开始)
//rk[i]就是suffix(i)的字典序排名,sa[i]就是要求的排名为i的后缀的起始位置,即rk[sa[i]]=i
for(int i=;i<=m;++i) c[i]=;
for(int i=;i<=n;++i) x[i]=a[i]-'a'+;
//x[i]用于存储suffix(i)的第一关键字(的排名),在刚开始长度为1的时候就是a[i]
//也就是,第i个后缀的第一关键字在所有后缀里的排名,记住定义!!!
//如果出于某些原因想加入一个空字符(字典序最小),那么在全局把它设置为'a'-1就好了,这也是为什么m=27而非26
for(int i=;i<=n;++i) c[x[i]]++;
//看起来十分草率的一个扔进桶里的过程
for(int i=;i<=m;++i) c[i]+=c[i-];
//把桶做一遍前缀和。这样操作后就有如果是s[i]=x,则c[x-1]<rk[i]<=c[x]
//也就是对于一个c[x-1]<p<=c[x],suffix(sa[p])的第一关键字为x
for(int i=;i<=n;++i) sa[c[x[i]]--]=i;
//这句话就是对第12~13行的那句话的一种实现方式
for(int len=;len<=n;len<<=){
//len表示的是第一关键字与第二关键字分别的长度,所以len<<1就是本轮真正所要比较的长度
//定义y数组,表示第二关键字排名为i的后缀是suffix(y[i])
int num=;
//num就是用来存储已经排好序的第二关键字的数量
for(int i=n-len+;i<=n;++i) y[++num]=i;
//suffix(i)的第二关键字现在是a[i+len...i+2len-1]。而对于suffix(n-len+1)...suffix(n)已经没有第二关键字了。
//而空字符的字典序最小,所以它们第二关键字的排名最靠前
for(int i=;i<=n;++i) if(sa[i]>len) y[++num]=sa[i]-len;
//对于所有p>len,a[p...p+len-1]这一截都会成为suffix(p-len)的第二关键字
//而你枚举的是sa[i],i从小到大也就是代表你从小到大枚举的所有可能出现的第二关键字
//现在y数组里面已经按从小到大的顺序存储好了所有可能出现的第二关键字,包括空的
//注意y数组的含义,和x是不一样的,x是位置i的第一关键字的排名,y是排名为i的第二关键字的位置
for(int i=;i<=m;++i) c[i]=;
for(int i=;i<=n;++i) c[x[i]]++;
for(int i=;i<=m;++i) c[i]+=c[i-];
//都与倍增外面的部分同理。还是按照第一关键字扔桶。下面要基数排序加入第二关键字了。
for(int i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
//这句话是最麻烦的一句,x[y[i]]表示第二关键字排名为i的后缀的第一关键字
//注意这里的循环需要倒序,因为你是从大到小枚举第二关键字,而由于你的c[]--,所以得到的排名也是从大到小
//这里和第12~13行的注释是同理的,注意每个按关键字排序后的后缀所在的排名区间
//所以也可以改写成for(int i=1;i<=n;++i) sa[++c[x[y[i]]-1]]=y[i];这样全文就都是正序枚举了不易混,但是需要清空c[0]
//我倾向于这个写法,实测可以AC。但是这里还是抄的wzz的原版板子,你们自行选择
for(int i=;i<=n;++i) y[i]=x[i],x[i]=;
//数组的回收利用,只不过是换个数组存了一下第一关键字,清空一个数组备用
x[sa[]]=m=;
//排名最小的串,它在2len长度比较下也最小,所以在下次len<<=1后,它对应的len第一关键字就是最小的第一关键字
//这里把m置为1.也就是现在要重新规定字符集大小了,这个1是是x[sa[1]],m以后表示的就是目前已知的本质不同后缀数
for(int i=;i<=n;++i) x[sa[i]]=(y[sa[i]]==y[sa[i-]]&y[sa[i]+len]==y[sa[i-]+len])?m:++m;
//这时候sa在2len长度的比较下已经排好序了,可以直接按照排名枚举。只要你和你前一名的第一/二关键字不完全相同
//那么你们就是不同的,所以你就是一个新串,加入字符集m++,然后重新给它在下一轮的第一关键字编号为m
if(m==n)break;
//如果你的字符集个数等于后缀个数,那么就是所有的后缀都被两两区分开了,可以提前跳出了
}
for(int i=;i<=n;++i)rk[sa[i]]=i;
//rk是suffix(i)的排名,从含义上就知道它是sa的逆数组
}

SA详细注释不压行代码的更多相关文章

  1. 自己总结的关于图论的一些算法实现(C语言实现,有较详细注释,800行左右)

    1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #define TRUE 1 5 # ...

  2. 阿里天池 NLP 入门赛 TextCNN 方案代码详细注释和流程讲解

    thumbnail: https://image.zhangxiann.com/jung-ho-park-HbnqEhMBpPM-unsplash.jpg toc: true date: 2020/8 ...

  3. Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果

    Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果 一.详细说明及代码 tc.py =============================================== ...

  4. python学习笔记(五)---sublime text 多行代码注释快捷键

    转载网址:https://blog.csdn.net/mycms5/article/details/70194045/ 多行选择后按下ctrl+/ 选择类 Ctrl+D 选中光标所占的文本,继续操作则 ...

  5. sublime text 多行代码注释快捷键

    多行选择后按下ctrl+/ 选择类 Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中 ...

  6. pycharm多行代码同时注释、去除注释

    pycharm中同时注释多行代码快捷键: 代码选中的条件下,同时按住 Ctrl+/,被选中行被注释,再次按下Ctrl+/,注释被取消

  7. Umi + Dva的数据传递学习Demo(代码有详细注释)

    刚学习时写了篇笔记,以免自己忘记,用了一段时间后,觉得不如做个demo,代码写上注释,方便也在学习umi-dva的同学们理解更好,更容易上手. 这可能是网上注释最多,看了最易理解的学习小指南吧,哈哈. ...

  8. C#/WPF/WinForm/.NET程序代码实现软件程序开机自动启动的两种常用方法的示例与源码下载带详细注释-源码代码-注册表方式-启动目录快捷方式

    C#/WPF/WinForm/.NET程序代码实现软件程序开机自动启动的两种常用方法的示例与源码下载带详细注释-源码代码-注册表方式-启动目录快捷方式 C#实现自动启动的方法-两种方法 源码下载地址: ...

  9. 一套强大的vim配置文件+详细注释

    phpchina折腾王独家配置,灰常牛叉的一套vim配置,另附有详细注释,自己折腾vim的时候可以参照其中的大部分设置进行一些个性化定制."是否兼容VI,compatible为兼容,noco ...

随机推荐

  1. HTTP请求流程你了解了么?

    我又回来了,先来波推广,最硬的资源来自公众号:前端美食汇,欢迎大家关注公众号获取最新的技术.提示,文末有福利,最硬的文章会首先发布在公众号上喔 预备知识 前文没有描述到传输和协议直接的层级对应关系,大 ...

  2. Python流程控制之循环结构

    目录 while循环 for循环 嵌套循环 break.continue.pass 练习 当出现有规律或者是重复的事情就可以使用循环. 1.循环变量初始化 2.循环条件 3.循环体 4.改变循环变量 ...

  3. 页面导入样式时,使用link和@import有什么区别

    link和@import两种导入样式表的方法比较 link属于HTML标签,而@import是CSS提供的 页面被加载的时候,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载 ...

  4. 一篇文章搞清楚HashMap和TreeMap的内部结构

    一.HashMap 1.基于哈希表的 Map 接口的实现. 此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Has ...

  5. python爬虫--代理.让你的ip在坚挺一会!!

    代理 代理简述 代理服务器:实现请求转发,从而可以实现更换请求的ip地址 在requests中如何将请求的ip进行更换 代理的匿名度: 透明:服务器知道你使用了代理并且知道你的真实ip 匿名:服务器知 ...

  6. JS中原始值和引用值分析

    JS中变量中两种类型的值:原始值,引用值 原始值是存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置. var x = 1; //1就是一个原始值,变量x中存放的就是原始 ...

  7. c++之运算符

    运算符分为:算数运算符.赋值运算符.比较运算符.逻辑运算符 算数运算符:+(正) -(负) + - * / % i++(先赋值后自增) ++i(先自增后赋值) i--(先赋值后自减) --i(先自减后 ...

  8. CAD绘图效率低?教你4个CAD绘图技巧,绘图效率提升十倍

    CAD绘图一直是一个谜一样的存在,说它简单吧,很多人都无法完全精通,说它难吧,很多人也都自学成才了. 如何学好CAD绘图是个难题,但是老话说的好,只要思想不滑坡,办法总比困难多,掌握以下这些CAD绘图 ...

  9. JS获取包含当前节点本身的代码内容(outerHtml)

    原生JS DOM的内置属性 outerHTML 可用来获取当前节点的html代码(包含当前节点),且此属性可使用jQuery的prop()获取 <div id="demo-test-0 ...

  10. windows客户端访问FTP服务器

    客户端访问FTP服务器步骤: 首先双击此电脑,在弹出的窗口输入如下信息 刚安装完的FTP服务器只有一个pub目录,因为这里是使用匿名用户登录的 FTP服务器默认的匿名目录在/var/ftp/pub/下 ...