后缀数组模版 及 可重叠和不可重叠最长重复子串【for_wind】

最近做了些机试题目,有道题目(不重复最长重复子串)测试时没想出有效解法,后来看到后缀数组,额,强大啊。记录之,分享之。有错误的地方,请留言啊,谢谢亲们~~~~~~~~~~~~~~~~~

概念部分,请查看参考资料2、3哦

//for_wind

一、后缀数组

(1)基本概念

1、字符串的大小比较:

        关于字符串的大小比较,是指通常所说的 “ 字典顺序 ” 比较。如a<b,aab<ab,a<ab。

 注:从字符串的大小比较的定义看,字符串s的所有后缀中任其中一对(u,v)不可能会相等,因为必要条件 len(u) ≠ len(v)不可能满足。所以任一字符串s中有len(s)个互不相同的后缀。我们可以将s的所有后缀排列,利用 后缀数组sa 与 名次数组rank 储存。 

2、后缀数组sa

        将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置。

  • 简单的记忆就是“排第几的是谁”。

3、名次数组rank

        rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次。则 若 sa[i]=j,则 rank[j]=i。

  • 简单的记忆就是“你排第几”。

4、sa和rank的关系        

        对于 后缀数组sa 与 名次数组rank ,有 rank[ sa[i] ]=i

(这是很重要的一点,通过sa与rank的关系可以求出后缀数组)

  • 由此可看出,后缀数组sa 与名次数组rank的关系为互逆关系。


Figure 1字符串aabaaaab的sa数组与rank数组

(2)倍增算法

1、主要思路:

        倍增,s[i..i + 2^k − 1]的排名通过s[i..i + 2^(k − 1) − 1]和s[i + 2^(k − 1) − 1..i + 2^k] 的排名得到。

2、简要过程。

        略。请参考最下面的参考资料3。嘻嘻。


Figure2倍增算法的计算过程

3、时间复杂度

        每一趟的计数排序的时间复杂度是O(n),排序的次数共log n次,总的时间复杂度为O(n log n)

(3)最长公共前缀:

        通常我们需要由rank与sa数组计算出一个辅助工具height数组——最长公共前缀(LCP)。

1、主要思想

        height 数组: 定义height[i]=suffix(sa[i-1]) 和 suffix(sa[i]) 的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀

        由height数组可得,对于j和k ,不妨设rank

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是使用 JS 后缀数组方法实现遍历主串所有子串并返回重复子串重复次数的代码: ```javascript function findRepeatSubstr(str) { let suffixArr = buildSuffixArray(str); // 构建后缀数组 let maxRepeatCount = 0; // 最大重复次数 let repeatSubstrs = new Set(); // 重复子串集合 for (let i = 0; i < suffixArr.length - 1; i++) { let j = i + 1; let repeatCount = 0; // 当前重复次数 // 比较相邻后缀 while (suffixArr[i].startsWith(suffixArr[j]) || suffixArr[j].startsWith(suffixArr[i])) { repeatCount++; j++; // 更新最大重复次数和重复子串集合 if (repeatCount > maxRepeatCount) { maxRepeatCount = repeatCount; repeatSubstrs.clear(); repeatSubstrs.add(suffixArr[i].substring(0, repeatCount)); } else if (repeatCount === maxRepeatCount) { repeatSubstrs.add(suffixArr[i].substring(0, repeatCount)); } } } return { repeatSubstrs: Array.from(repeatSubstrs), maxRepeatCount }; } // 构建后缀数组 function buildSuffixArray(str) { let suffixes = []; for (let i = 0; i < str.length; i++) { suffixes.push(str.slice(i)); } suffixes.sort(); let suffixArr = suffixes.map(suffix => str.length - suffix.length + 1); return suffixArr; } ``` 该函数接受一个字符串作为参数,并返回一个对象,包含重复子串重复次数。其中,重复子串以数组形式返回,重复次数为一个整数。 例如,对于字符串 `"banana"`,调用 `findRepeatSubstr("banana")` 将返回以下结果: ```javascript { repeatSubstrs: ['an'], maxRepeatCount: 2 } ``` 表示字符串中有一个重复子串 `"an"`,重复了两次。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值