Poj 2774 Long Long Message (后缀数组)
2015-09-04 17:19
204 查看
题目链接:
Poj 2774 Long Long Message
题目描述:
给出A,B两个字符串,求最长公共子串?
解题思路:
求A,B字符串的最长公共子串可以转化为求A,B字符串后缀数组的最长公共前缀。把B串连接在A串后面,用'$'隔开组成r串。求出r串的height数组,最大的height[i](满足sa[i]与sa[i-1]不在同一文本串中)就是答案。时间复杂度大概为O((|A|+|B|)*log(|A|+|B|))。(阅兵假期用来搞这个,感觉还是有点怪怪的感觉,不过秉承着以前的学习风格,先记下模板,以后在水题中慢慢体会好了)
Poj 2774 Long Long Message
题目描述:
给出A,B两个字符串,求最长公共子串?
解题思路:
求A,B字符串的最长公共子串可以转化为求A,B字符串后缀数组的最长公共前缀。把B串连接在A串后面,用'$'隔开组成r串。求出r串的height数组,最大的height[i](满足sa[i]与sa[i-1]不在同一文本串中)就是答案。时间复杂度大概为O((|A|+|B|)*log(|A|+|B|))。(阅兵假期用来搞这个,感觉还是有点怪怪的感觉,不过秉承着以前的学习风格,先记下模板,以后在水题中慢慢体会好了)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 200010; int sa[maxn], rank[maxn], height[maxn]; int t1[maxn], t2[maxn], r[maxn], c[maxn]; bool cmp (int *str, int a, int b, int k) {//rank相邻的两个串,第一第二关键字都一样,rank一样 return str[a]==str[b] && str[a+k]==str[b+k]; } int da (int *str, int n, int m) { int *x = t1, *y = t2, i, j; n ++; //基数排序, for (i=0; i<m; i++) c[i] = 0; for (i=0; i<n; i++) c[x[i] = str[i]] ++; for (i=1; i<m; i++) c[i] += c[i-1]; for (i=n-1; i>=0; i--) sa[-- c[str[i]]] = i; for (j=1; j<=n; j*=2) { //用sa数组对第二关键字排序 int p = 0; for (i=n-j; i<n; i++) y[p++] = i; //不能添加长度为j的串,第二关键字附为最小 for (i=0; i<n; i++) if (sa[i] >= j) y[p++] = sa[i] - j; //枚举rank,起点大于j的串,才能倍增 //更新sa数组 for (i=0; i<m; i++) c[i] = 0; for (i=0; i<n; i++) c[x[y[i]]] ++; for (i=1; i<m; i++) c[i] += c[i-1]; for (i=n-1; i>=0; i--) sa[-- c[x[y[i]]]] = y[i]; //更新x数组 swap (x, y); p = 1, x[sa[0]] = 0; for (i=1; i<n; i++) x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++; if (p >= n) break; m = p; } //计算rank数组 for (i=0; i<n; i++) rank[sa[i]] = i; //计算height数组 n --; int k = 0; for (i=0; i<n; i++) {//枚举起点, height[名次] if (k) k --; j = sa[rank[i]-1]; while (str[i+k]==str[j+k]) k++; height[rank[i]] = k; } } int main () { char str1[maxn/2], str2[maxn/2]; while (scanf ("%s %s", str1, str2) != EOF) { int n1 = strlen(str1); int n2 = strlen(str2); int n = n1 + n2 + 1; for (int i=0; i<n; i++) { if (i < n1) r[i] = str1[i]; else if (i == n1) r[i] = '$'; else r[i] = str2[i-n1-1]; } r = 0; da (r, n, 128); int ans = 0; for (int i=1; i<n; i++) {//i为rank if (sa[i]<n1&&sa[i-1]>n1 || sa[i]>n1&&sa[i-1]<n1) //rank相邻的后缀串不在同一个字符串 ans = max(ans, height[i]); } printf ("%d\n", ans); } return 0; }
相关文章推荐
- XML Schema
- linux入门教程(九) 文本编辑工具vim
- 用VB实现COM+组件配置
- 【白书之路】1225 - Digit Counting 数字统计
- 权限的设计
- WMI获取计算机信息
- HDU 1693 Eat the Trees (插头DP)
- CMCC-EDU 模拟登陆中的验证码识别
- JNI开发之 c++输出日志到Logcat
- 设计模式之工厂方法模式
- Java线程通信练习之“生产者/消费者问题”
- LAMP php5.4编译
- 注册表语法
- hdoj 1002 A + B Problem II 【大数加法模板】
- 全排列和全组合
- HDU 3966 Aragorn's Story(树链剖分)
- 2013完美世界校招笔试题及答案
- 解决Android AVD启动报错问题
- 【转】keySet和entrySet的区别
- 汇编指令