首页 > 其他分享 >后缀排序

后缀排序

时间:2023-07-27 09:44:19浏览次数:31  
标签:suff 后缀 int sa 排序 rk

后缀排序

本文做复习用,不宜初学用。

定义

\(sa\) 表示排名为 \(i\) 的位置。

\(rk\) 表示位置为 \(i\) 的排名。

\(y\) 表示按照第二关键字排序排名为 \(i\) 的位置。

\(height\) 表示排名为 \(i\) 和 \(i - 1\) 的后缀的最大前缀

\(h\) 表示位置为 \(i\) 和它排名前一位的后缀的最大前缀

操作流程

最初字符串排序

这里是桶排序基础操作。

for(int i = 1; i <= n; ++i) ++c[rk[i] = a[i]];
for(int i = 1; i <= m; ++i) c[i] += c[i - 1];
for(int i = n; i >= 1; ++i) sa[c[rk[i]--] = i;//按照1,2,3的顺序排

为什么是倒叙的呢?你用手模拟一下ababa这个样例就懂了

进行倍增比较操作。

for(int i = 1; i <= n; i <<= 1)

第二关键字排序

这里是把最后那一部分没有第二关键字的放在最前面。

num = 0;
for(int i = n - k  + 1; i <= n; ++i) y[++num] = i;

对有第二关键字的排序。按照 \(sa\) 数组,也就是排名进行。

for(int i = 1; i <= n; ++i) if(sa[i] - k > 0) y[++num] = sa[i] - k;

总体排序

清空桶。

for(int i = 1; i <= m; ++i) c[i] = 0;

这里先按照 \(rk\) 排序,和最初字符串排序有点类似。

for(int i = 1; i <= n; ++i) ++c[rk[i]];
for(int i = 1; i <= m; ++i) c[i] += c[i - 1];
for(int i = n; i >= 1; --i) sa[c[rk[y[i]--] = y[i];//按照y[i]的顺序排

更新 \(rk\) 数组和 \(m\)

这里把 \(y\) 和 \(rk\) 交换其实就是用 \(y\) 暂时存储上一次的 \(rk\) 。

比较当前 \(sa[i]\) 和 \(sa[i - 1]\) 是否完全相等。如果相等就和 \(sa[i-1]\) 赋一样的 \(num\)

swap(rk,y);num = 0;
for(int i = 1; i <= n; ++i)
    rk[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && sa[i] + k <= n && sa[i - 1] + k <= n && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
if(num == n) break;
m = num; num;

LCP

定义

\(suff(i)\) 表示以 i 开头的后缀。

\(height[i]\) 表示排名为 \(i\) 与排名为 \(i-1\) 的后缀字符串的前缀。

\(h[i]\) 表示位置为 \(i\) 与它的排名\(-1\) 的后缀字符串的前缀。

形式化的:

\[height[i] = lcp(suff(sa[i]),suff(sa[i - 1]))\\ h[i] = height[rk[i]],height[i] = h[sa[i]] \]

有这样的好性质:

\[h[i] \ge h[i - 1] - 1 \\ lcp(suff(i),suff(j)) = \min_{x = rk[i] + 1} ^ {rk[j]}lcp(suff(sa[x]),suff(sa[x - 1])) = \min_{x = rk[i] + 1} ^ {rk[j]} height[x] \]

所以要算 \(lcp\) 直接用一个 \(RMQ\) 就可以了。

求 h 数组

这里很好理解。

for(int i = 1; i <= n; ++i){
		h[i] = h[i - 1] - 1;
		if(h[i] < 0) h[i] = 0;
		while(a[sa[rk[i]] + h[i]] == a[sa[rk[i] - 1] + h[i]] ) ++h[i];
	}

标签:suff,后缀,int,sa,排序,rk
From: https://www.cnblogs.com/hfjh/p/17584110.html

相关文章

  • sort排序
    数值排序: arr.sort((a,b)=>a.id-b.id); 字符串排序:varcompare=function(a,b){      if(a.name<b.name){        return-1;      }elseif(a.name>b.name){        return1;   ......
  • 算法学习笔记(27): 后缀排序
    后缀排序本文做复习用,不宜初学用。开篇膜拜Pecco:算法学习笔记(84):后缀数组-知乎(zhihu.com)有些时候,其实\(O(n\log^2n)\)的排序也挺好。又短又简单。其中\(rk[i]\)表示从第\(i\)个字符开始的后缀的排名,\(sa[i]\)表示排名为\(i\)的后缀开始的位置。#includ......
  • 数据库常用字符集及排序规则
    字符集是指在计算机中用来表示字符的编码方式。不同的字符集包含了不同的字符集合,并且每个字符都有一个唯一的编码。在MySQL中,字符集是指在数据库中存储和处理数据时所使用的字符编码方式。1、字符集1、utf8UTF-8是MySQL中最常用的字符集,它支持多语言字符集,包括中文、......
  • js字符串数据排序
    results=[{model:'CM201-2'},{model:'CM201-3'},{model:'CM201-6'},{model:'H1Ne-02-1'},{model:'MGV200'},{model:'UNT400G1'},]results.sort((a,b)=>{returna.model.localeCompare(b.model)}); ......
  • npm常用后缀
    –--save、-S参数意思是把模块的版本信息保存到dependencies(生产环境依赖)中,即你的package.json文件的dependencies字段中;–--save-dev、-D参数意思是把模块版本信息保存到devDependencies(开发环境依赖)中,即你的package.json文件的devDependencies字段中;–--save-optional......
  • C#-实现对版本号的自动排序
    前提是版本号都是Vxx.xx.xx.xx....的格式,xx代表数字,不能有除V以外其他字母记录两种比较方法,一种是vs自带的Version类,一种是自己写的,根据比较结果,使用冒泡排序进行排序。先给出一堆乱序的版本号:List<string>verList;privatevoidInitVersion(){verList=newList<str......
  • [Java] Stream流求和、排序、分组
    List、Set集合通过Stream流求和一、泛型为Integer、Long、Double、BigDecimal求和Integersum=scores.stream().reduce(Integer::sum).orElse(0);Longsum=scores.stream().reduce(Long::sum).orElse(0L);Doublesum=scores.stream().reduce(Double::sum).orElse(0.00)......
  • Tableau 分组排序,并显示前几名()
    待更新1、index+rank 2、LOD表达式+ PERCENTILE()①各个子类别下95%以下的数据,对这部分数据进行统计计算: [销售额]<=  {FIXED[子类别]:PERCENTILE([销售额],0.95)} ②在别处查到的,暂时不知道怎么用,先记录在此:......
  • 简单选择排序
    本文章的代码使用jetbrains公司旗下的的Clion编写,操作系统位macOSVentura(13.2.1).代码没有在dev-c++测试过(dev-c++可能会有相关的空格问题)////Createdby魏志杰on2023/7/25.//#include"stdio.h"#defineMax100#definebeforeprintf("排序前")#defineafterp......
  • [c/c++][考研复习笔记]内部排序篇学习笔记
    考研排序复习笔记插入排序#include<stdio.h>#include<stdlib.h>#defineMaxSize9//折半插入排序voidZBInsertSort(intA[],intn){ inti,j,high,low,mid; for(i=2;i<=n;i++){ A[0]=A[i]; low=1;high=i-1; while(low<=high){ mid=(low+high)/2......