LCP数组的实现和最长公共连续子串
来源:互联网 发布:微博个性域名怎么删除 编辑:程序博客网 时间:2024/05/21 10:51
LCP数组(Longest Common Prefix Array, 高度数组):是由后缀数组中相邻两个后缀的最长公共前缀的长度组成的数组。
假设字符串S, 后缀数组sa, LCP数组lcp, 那么有后缀S[sa[i]...]与S[sa[i + 1]...]的最长公共前缀的长度为lcp[i]。
lcp的计算: (后缀数组的实现)假设S[i...]与S[sa[rank[i]]...]的前h个字符的长度相等, 那么S[i+1...]与S[sa[rank[i + 1]]...]的前h - 1个字符也相等。 那么可以在O(n)的时间内求出lcp哦。
lcp的简单应用:
1)求一个字符串中出现次数至少两次的最长子串的长度。比如abracadabra,那么结果为4(abra出现两次且最长)。那么怎么利用lcp来求出答案呢?由后缀数组和lcp的性质可以知道,子串的开始位置在后缀数组中相距越远,其公共前缀的长度也就越短。找出lcp中最大的值,就是答案了。
2)求两个字符串的最长公共连续子串。利用上面的结论,可以把两个字符串连接起来,然后对其求lcp即可。
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define MAX_N 10005#define max(a, b) (a > b ? a : b)char strA[MAX_N], strB[MAX_N], strC[MAX_N*2 + 5];int sufArr[MAX_N], lcp[MAX_N], rank[MAX_N], temp[MAX_N];int n, k;bool compareSufArr(int i, int j) {int ri, rj;if (rank[i] != rank[j]) {return rank[i] < rank[j];} else {ri = i + k <= n ? rank[i + k] : -1;rj = j + k <= n ? rank[j + k] : -1;return ri < rj;}}void constructSufArr(char* str, int* sa, int len) {int i;n = len;for (i = 0; i <= n; i++) {sa[i] = i;rank[i] = i < n ? str[i] : -1;}for (k = 1; k <= n; k *= 2) {sort(sa, sa + n + 1, compareSufArr);temp[sa[0]] = 0;for (i = 1; i <= n; i++) {temp[sa[i]] = temp[sa[i - 1]] + (compareSufArr(sa[i - 1], sa[i]) ? 1 : 0);}for (i = 0; i <= n; i++) {rank[i] = temp[i];}}}// 构造后缀数组的lcpvoid constructLcp(char* str, int* sa, int* cp, int len) {int i, j;int h;for (i = 0; i <= len; i++) {rank[sa[i]] = i;}h = 0;cp[0] = 0;for (i = 0; i < len; i++) {j = sa[rank[i] - 1];if (h > 0) {--h;}while (i + h < n && j + h < n && str[i + h] == str[j + h]) {++h;}cp[rank[i] - 1] = h;}} // O(n)// 求一个字符串中出现过的最长重复子串int lrs(char* str) {int len;int res;int i;len = strlen(str);constructSufArr(str, sufArr, len);constructLcp(str, sufArr, lcp, len);res = 0;for (i = 0; i < len; i++) {res = max(res, lcp[i]);}return res;}// 求两个字符串的最长公共连续子串int lcs(char* ms, char* ss) {int ml, sl, len;int res;int i;ml = strlen(ms), sl = strlen(ss);// strC = ms + '\0' + ssstrcpy(strC, ms);strC[ml + 1] = '\0';strcpy(strC + ml + 2, ss);// 对strC求后缀数组和lcplen = ml + sl + 2;constructSufArr(strC, sufArr, len);constructLcp(strC, sufArr, lcp, len);//res = 0;for (i = 0; i < len; i++) {// 需要分属不同的字符串,否则就变成了在同一个字符串中求最长公共连续子串的长度if ((sufArr[i] < ml) != (sufArr[i + 1] < ml)) {res = max(res, lcp[i]);}}return res;}int main() {while (scanf("%s%s", strA, strB) != EOF) {printf("%d %d\n", lrs(strA), lrs(strB));printf("%d\n", lcs(strA, strB));}return 0;}
qbvdvghj suffixarrayabracadabra suffixarraysuffixarray abracadabraabcdefg abcdefgxyzqu iopcye
- LCP数组的实现和最长公共连续子串
- “最长上升子序列,最大连续子序列和,最长公共子串”的Java实现
- 利用后缀数组 前缀 LCP最长公共前缀求第K大的子串
- 最长公共连续子串和最长连续公共子序列
- 最长公共连续子串
- 最长公共连续子串
- 最长连续公共子串
- 最长公共子串--后缀数组实现
- 最长连续子数组的和
- 求两个字符串的最长公共子串(包括连续和非连续)
- LCP poj 2217 寻找最长公共子串
- Python最长公共子串和最长公共子序列的实现
- 最长公共子序列(LCS)和最长公共连续子串
- 求两个字符串的最长的连续公共子串和求两个字符串的公共子序列
- 经典字符串算法 “最长上升子序列,最大连续子序列和,最长公共子串”
- 求两个字符串的最长的连续公共子串
- 求两个字符串的最长的连续公共子串
- 求两个字符串的最长的连续公共子串
- Project Euler problem 61
- eclipse远程debug 设置
- linux 删除文件名为乱码的文件方法
- PHP架构-PHP内核
- 内存泄漏以及常见的解决方法
- LCP数组的实现和最长公共连续子串
- UVa 340 Master-Mind Hints (优化查找&复制数组)
- 《C专家编程》读后记
- struts2常用知识
- 【系列】Latex-1
- hdu 3277 (二分+并查+最大流)
- c/c++接口嵌入式sqlite使用小结
- CMS工作原理
- ArcGIS 10、ERDAS 9.2安装