数据结构-后缀数组

后缀数组

学习了一下后缀数组。这个题目是后缀数组里面比较经典的一种。

后缀数组有几个比较经典的应用

  • 求最长公共子串
  • 求最长公共前缀
  • 求可重叠的最长公共子串
  • 求不可重叠的最长公共子串

后缀数组主要是用于把一个字符串的后缀排序。

先说几个常用的数组
sa数组:sa[i]表示排名为i的后缀在原串中的起始位置是多少
rank数组:rank[i]表示起始位置为i的后缀排名第几
h数组:h[i]表示排名第i的后缀和排名第i-1的后缀的最长公共前缀(lcp)是多少

主要的计算过程都是在计算rank数组。得到rank数组后一个for循环可以得到sa数组。然后两个for循环可以得到h数组。

计算方法

rank数组的计算

以下认为起始下标是1。

每个后缀需要记录它的前一半字符串的排名(第一关键字),后一半字符串的排名(第二关键字),以及这个串的起始下标。

首先实现一个基数排序。后缀数组不再将两个串的字符进行比较,而是利用倍增的方式,每次比较都是二元组的比较。基数排序是从低位开始,先对低位排序,再对高位排序。每次排序都使用桶排序。基数排序实际上,是先把每个元素放到对应的桶里。然后从前往后把所有桶的结果加起来得到cnt。这样可以得到每个桶里元素的结束位置+1的下标值。最后从后往前遍历,遇到一个元素,就放在对应cnt记录的位置里,放之前要把位置减1。

排序之后,得到一个长度为k的后缀的排名。遍历这个排好序的结果,计算rank数组的值。一样的字符串排名相同,采用1 1 2 2 3这样的编码。

接下来要计算长度为k * 2的后缀的排名,于是把之间计算得到的结果拼接成二元组。然后基数排序。

当后缀没有第二个元素时,补0。所以从1开始下标。

sa数组计算

sa和rank可以互推。即

sa[rank[i]] = i。

h数组计算

从左往右计算h数组。可以推出

h[i] >= h[i - 1] - 1

最长公共前缀lcp

最长公共前缀有如下关系

LCP(s[i], s[j]) = min{LCP(s[k], s[k+1]), i <= k <= j}

即,两个后缀的lcp是它们之间的字符串两两之间lcp的最小值。两两之间的lcp就是h数组,所以就是h数组的最小值。

几个经典问题

最长公共子串

  • 连接两个字符串
  • 计算后缀数组
  • 计算h数组
  • 排名相邻但原来不在一个字符串中的两个后缀的h值的最大值

不可重叠最长重复子串

也有可重叠的版本,比这个简单。

  • 连接两个字符串
  • 计算后缀数组
  • 计算h数组
  • 二分一个k值,这个k值把h数组分成若干组,每组内的h数组都大于等于k。所以每组的任意两个串的最长公共前缀都是至少k。记录每组下标的最大值和最小值,然后判断这个差是否大于等于k。如果满足,那么就是不可重叠的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值