后缀数组

学习后缀数组笔记

六月ゝ 毕业季﹏ 提交于 2020-01-19 02:51:07
  学习自:https://www.cnblogs.com/victorique/p/8480093.html 后缀:是字符串的一个特殊子串,以s的第i个字符为第一个元素的后缀为suff(i)。 后缀数组:后缀数组sa[i]就表示排名为i的后缀的起始位置的下标。 相反映射:rk[i]就表示起始位置的下标为i的后缀的排名。 倍增法+基数排序实现后缀数组O(nlogn)排序:思想是先对首字符排序(重复),在对相邻相加再排序,直到所有排名不同即可。(需进一步理解) 最长公共前缀: 我们定义LCP(i,j)为suff(sa[i])与suff(sa[j])的最长公共前缀。 LCP(i,j)=LCP(j,i); LCP(i,i)=len(sa[i])=n-sa[i]+1; LCP引理   LCP(i,k)=min(LCP(i,j),LCP(j,k)) 对于任意1<=i<=j<=k<=n LCP定理   LCP(i,k)=min(min(LCP(j,j-1))) 对于1<i<=j<=k<=n 重要定理: 我们设height[i]为LCP(i,i-1),1<i<=n,显然height[1]=0; 由LCP Theorem可得,LCP(i,k)=min(height[j]) i+1<=j<=k 设h[i]=height[rk[i]],同样的,height[i]=h[sa[i]]; 有:     h

后缀数组

。_饼干妹妹 提交于 2020-01-19 02:50:17
后缀数组个人感觉的确有点复杂,看了挺久的,听说后缀数组是一种神仙操作,忘记在哪听到这个就学了一下 学习博客:https://www.cnblogs.com/victorique/p/8480093.html 什么是后缀数组 我们先看几条定义: 子串 在字符串s中,取任意i<=j,那么在s中截取从i到j的这一段就叫做s的一个子串 后缀 后缀就是从字符串的某个位置i到字符串末尾的子串,我们定义 以s的第i个字符为第一个元素的后缀为suff(i) 后缀数组 把s的每个后缀按照字典序排序, 后缀数组sa[i]就表示 排名为i的后缀 的起始位置的下标 而它的映射数组rk[i]就表示 起始位置的下标为i的后缀 的排名 简单来说,sa表示排名为i的是啥,rk表示第i个的排名是啥 一定要记牢这些数组的意思,后面看代码的时候如果记不牢的话就绝对看不懂 后缀数组的思想 先说最暴力的情况,快排(n log n)每个后缀,但是这是字符串,所以比较任意两个后缀的复杂度其实是O(n),这样一来就是接近O(n^2 log n)的复杂度,数据大了肯定是不行的,所以我们这里有两个优化。 ps:本文中的^表示平方而不是异或 倍增 首先读入字符串之后我们现根据单个字符排序,当然也可以理解为先按照每个后缀的第一个字符排序。对于每个字符,我们按照字典序给一个排名(当然可以并列),这里称作关键字。

编译原理 语义分析

故事扮演 提交于 2020-01-14 02:28:20
文章目录 1. 语义与语法的区别 重点:语义分析的两个作用 <3> 语义分析的方法 2. 中间代码 重点:要求中间代码具有如下特性,以便于编译器的开发移植和代码的优化: 3.后缀式 定义 算法实现 4.后缀式的计算 5.三地址码 6.四元式主要由四部分组成: 三地址代码 例题有文法 G 和 G 的语法制导翻译如下: 7.符号表 8. 数组元素的引用 9. 布尔表达式 10. 控制语句 11.过程的定义与声明 左值和右值 拉链回填 1. 语义与语法的区别 <1> 语法与语义的关系 语法是指语言的结构、即语言的“样子”;语义是指附着于语言结构上的实际含意 ,即语言的“意义”。 对于语法和语义: 语义不能离开语法独立存在; 语义远比语法复杂; 同一语言结构可包含多种含意,不同语言结构可表示相同含意; 语法与语义之间没有明确的界线。 重点:语义分析的两个作用 1.检查是否结构正确的句子所表示的意思也合法; 2.执行规定的语义动作,如: 表达式求值 符号表填写 中间代码生成等 <3> 语义分析的方法 语法制导翻译 2. 中间代码 重点:要求中间代码具有如下特性,以便于编译器的开发移植和代码的优化: 便于语法制导翻译; 既与机器指令的结构相近,又与具体机器无关。 3.后缀式 定义 一个表达式E的后缀形式可以如下定义: (1)如果E是一个变量或常量,则E的后缀式是E本身。 (2)如果E是E1

KMP算法

烂漫一生 提交于 2020-01-10 11:58:04
字符串匹配 是计算机的基本任务之一。 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务, Knuth-Morris-Pratt算法 (简称KMP)是最常用的之一。它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth。 这种算法不太容易理解,网上有很多 解释 ,但读起来都很费劲。直到读到 Jake Boxer 的文章,我才真正理解这种算法。下面,我用自己的语言,试图写一篇比较好懂的KMP算法解释。 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。 2. 因为B与A不匹配,搜索词再往后移。 3. 就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。 4. 接着比较字符串和搜索词的下一个字符,还是相同。 5. 直到字符串有一个字符,与搜索词对应的字符不相同为止。 6. 这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。 7. 一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息

[POI2000]公共串 - 后缀数组

亡梦爱人 提交于 2020-01-07 12:25:19
Description 求若干个串的最长的公共子串的长度。 Solution 考虑将这若干个串全部拼起来,中间用一些不在字符集内的符号隔开。 然后二分答案 \(K\) ,如果连续的一段 \(height\) 都大于等于 \(K\) ,且每个串都出现了至少一次,则是可行的。 Code #include <bits/stdc++.h> using namespace std; const int _ = 1e5 + 10; int N, n, s[_], belong[_]; int rnk[_], sa[_], height[_]; char str[_]; void SA() { static int t[_], a[_], buc[_], fir[_], sec[_], tmp[_]; copy(s + 1, s + N + 1, t + 1); sort(t + 1, t + N + 1); int *end = unique(t + 1, t + N + 1); for (int i = 1; i <= N; ++i) a[i] = lower_bound(t + 1, end, s[i]) - t; fill(buc + 1, buc + N + 1, 0); for (int i = 1; i <= N; ++i) ++buc[a[i]]; for (int i = 1;

字符串练习题

故事扮演 提交于 2020-01-05 14:46:35
https://vjudge.net/contest/278181 写在前面: 1)一个子串既是一个后缀的前缀,又是一个前缀的后缀 2)AC自动机/后缀数组后常接DP/数据结构 Problem 0 Long Long Message (后缀数组) http://poj.org/problem?id=2774 思路: 两个字符串拼起来,求后缀数组和height数组 记录一下该后缀是从第一个字符串开始的还是第二个字符串开始的 对于从不同字符串开始的相邻位置的后缀 ans=max(height)(height表示的两个相邻后缀的起始位置为不同字符串才对答案有贡献) 为了避免从第一个字符串开始的后缀延伸到第二个字符串,造成结果可能会大,我们可以算各项结果时与在第一个字符串内长度取min,或者在两个字符串接起来的时候在中间加一个不可能被匹配的其他字符 Problem1 [BJWC2011]禁忌 (AC自动机) https://www.lydsy.com/JudgeOnline/problem.php?id=2553 https://www.luogu.org/problemnew/show/P4569 思路:f[i][j]表示已把前i位填好,走到AC自动机上j这个节点所有方案价值总和 枚举第i+1个位置填哪个字符 f[i][j]-> f[i+1][trans[j][k]] -> f[i+1]

后缀数组专题

不打扰是莪最后的温柔 提交于 2019-12-27 04:29:22
一、单个字符串问题   1、重复子串     ① 可重叠最长重复子串      分析:后缀的lcp就是子串的lcp,等价于求任意两个后缀的的最长公共前缀,任意两个后缀的最长公共前缀是这段height[]中的最小值,这个最小值一定小于整个height[]的最大值,所以结果就是height[]的最大值         O(n)     ② 不可重叠最长重复子串 (poj1743)      分析:二分k,表示是否存在长度为k的不重叠重复子串         然后对于height[]从前往后扫描一边,把那些相邻height[]>=k的放在一组         易得,如果答案存在,那么必定是某一组中间的两个后缀,不可能跨组         然后分析发现,一组中如果存在两个是不重叠的,那么他们的对应后缀长度的差应该是>=k的,所以只要找出每组中sa[]的最大值和最小值的差,判断是否大于等于K即可         O(nlogn)     ③ 可重叠的k次最长重复子串 (poj3261):给定一个字符串,求至少出现K次的最长重复子串,这些子串可以重叠      分析:和上一题方法类似,同样也是二分K,再分组,判定方法是看有没有一组的个数>=k,有就ok         O(nlogn)   2、子串的个数     ①给定一个字符串,求 不相同的子串的个数 (spoj705)      分析

POJ3294:Life Forms——后缀数组

我只是一个虾纸丫 提交于 2019-12-27 04:28:53
题面    POJ3294 解析    翻译一下题意:给定n个字符串,求最长的字符串 S 的长度,使得 S 至少为其中 n/2+1 个字符串的子串, 并输出所有的S,若不存在,则输出'?'。(n<=100)    此题与 POJ3261 类似(我的 博客 ),都是相同套路,后缀数组+二分答案   当然是把每个字符串连在一起,组成一个大的字符串,再在上面建立后缀数组。但是这里有个细节,搞了我很久,为了防止我们选出的子串跨越了原来的多个字符串,需要在每个字符串中间加入不同的不会出现的字符,这样就解决了这个问题。   check的时候需要维护每个块内的$lcp$出现在多少个原来的字符串中,开一个$bool$型的$vis$数组存原字符串是否在当前块内出现,再开一个$pos$数组存长字符串的下标所属的原字符串编号,对于字符串间加入的字符的$pos$等于0, 而$vis[0]$应永远等于$true$,不能对答案产生贡献   代码: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn = 105, maxm = 1005; int n, len, cur, timer, pos[maxn*maxm], s[maxn*maxm];

POJ 1743 后缀数组

送分小仙女□ 提交于 2019-12-27 04:27:31
题目链接:http://poj.org/problem?id=1743 题意:给定一个钢琴的音普序列[值的范围是(1~88)],现在要求找到一个子序列满足 1,长度至少为5 2,序列可以转调,即存在两个子序列,满足一个子序列加/减一个数后可以得到另一个序列 3,两个序列不能有相交的部分。 题意简单来说就是找最长不重叠的重复子串 思路:直接根据09年oi论文<<后缀数组——出来字符串的有力工具>>的解法,先二分答案,把题目变成判定性问题:判断是否存在两个长度为k 的子串是相同的,且不重叠。解决这个问题的关键还是利用height 数组。把排序后的后缀分成若干组,其中每组的后缀之间的height 值都不小于k。容易得出,有希望成为最长公共前缀不小于k 的两个后缀一定在同一组。然后对于每组后缀,只须判断每个后缀的sa 值的最大值和最小值之差是否不小于k。如果有一组满足,则说明存在,否则不存在。整个做法的时间复杂度为O(nlogn)。 对于第二点要求的转换,即转调条件,一个子序列加/减一个数后可以得到另一个序列实际是两个序列的变化程度是一样的,比如序列1 2 3 4 5 6 7 8 9 10 那么对于这个序列的可以得到长度为5的两个不相交的"转调后的重复子序列", 序列一:1 2 3 4 5(变化程度 1 1 1 1) 序列二:6 7 8 9 10(变化程度1 1 1 1)

POJ 1743:Musical Theme(后缀数组+二分)

☆樱花仙子☆ 提交于 2019-12-27 04:26:54
题目链接 题意 有N个音符的序列来表示一首乐曲,每个音符都是1到88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件: 长度至少为5个音符。 在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值) 重复出现的同一主题不能有公共部分。 思路 论文里面出现的题目。 因为加上和减去同一个整数值,就可以作差,因为减出来可能是个负数,因此需要+88. 二分答案,转化为是否存在两个长度为k的子串是相同的,且不重叠。 将height数组根据k分组,使得每组的后缀之间的height值都大于等于k,有希望成为最长公共前缀不小于k的两个后缀在同一组。 要使得两个串不重叠,只要判断同一组里面最大的sa值和最小的sa值的差大于等于k,这样就可以不重叠了。 #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; typedef long long LL; typedef pair<int, int> pii; const int INF = 0x3f3f3f3f; const int N = 2e5 + 11; int t1[N], t2[N], c[N], s[N], str[N]