poj 1226 求多串最长公共子串 或 回文子串 KMP&&strstr&&后缀数组
来源:互联网 发布:淘宝怎么没有朋友代付 编辑:程序博客网 时间:2024/06/06 03:49
题意:求给出的字符串中的最长公共子串 ,其中子串可以反转,比如rose 和 orchid , ro 和第一个匹配 , ro 的回文串or 和orchid 匹配 。最后输出最长子串的长度。
思路:找出长度最小的子串, 枚举其所有子串 ,然后将其反转再保存 ,最后用这两个串去匹配其它的字符串。
#include<iostream>#include<cstdio>#include<cstring>using namespace std;char str[52][505];char ss[305] , ts1[305] , ts2[305];int next[205];void get_next(char *T , int len) { /*****得到next数组*****/ int j = 0, k = -1; next[0] = -1; while (j < len) { if(T[j] == T[k] || k == -1) { next[j+1] = k+1; j++;k++; } else k = next[k]; } }int kmp(char *T , int h , int len2 , int len1) { /*****KMP*****/ int i , j; i = j = 0; while(i <len1 && j <len2) { if(T[j]==str[h][i] || j == -1) { j++;i++; }else { j = next[j]; } } if(j == len2) return 1; return 0; }int main() { int T , i , j , k , len , n , g , temp; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i = 0 ; i < n ; i ++) scanf("%s",str[i]); len = 120; for(i = 0 ; i < n ; i ++) { /*****找长度最小的字符串*****/ if(strlen(str[i]) <= len) { len = strlen(str[i]); temp = i; } } int tt , ans , cnt , l1 , l2 , lenn , f , flag , r , t; ans = 0; for(i = 1 ; i <= len ; i ++) { for(j = 0 ; j <= len - i; j ++) { for(g = 0 ,k = j ; k < j + i ; k ++ , g++) { /*****暴力枚举长度是i的最小字符串子串ts1*****/ ts1[g] = str[temp][k]; } ts1[g] = '\0'; for(tt = 0 ; tt < g ; tt ++) { /*****求这个子串的反转子串ts2*****/ ts2[tt] = ts1[g - tt - 1]; } ts2[tt] = '\0'; get_next(ts1 , i); /*****得到ts1的next数组*****/ cnt = 0; bool vis[100]; /*****标记数组*****/ memset(vis , false , sizeof(vis)); for(f = 0 ; f < n; f ++) { lenn = strlen(str[f]); if(kmp(ts1 , f , i , lenn) && !vis[f]) { vis[f] = 1; cnt++;} } get_next(ts2 , i); for(f = 0 ; f < n ; f ++) { lenn = strlen(str[f]); if(kmp(ts2 , f , i , lenn)&&!vis[f]) { vis[f] = 1; cnt++;} } /*****分别用ts1 、 ts1 去匹配其它串*****/ if(cnt == n) { //满足条件中取最长的子串长度 if(i > ans) ans = i; } } } printf("%d\n",ans); } }
strstr 函数水的~ 注意strncpy枚举子串的方法
#include<iostream>#include<cstdio>#include<cstring>using namespace std;char str[120][120];char s1[120] , s2[120];char zz1[120] , zz2[120];int main() { int n , T , i , j , k , t , temp; scanf("%d",&T); while(T--) { scanf("%d",&n); int len = 120; for(i = 0 ; i < n ; i ++) { scanf("%s",str[i]); int ll = strlen(str[i]); if(ll < len) { len = ll; temp = i; } } strcpy(s1 , str[temp]); int ans = 0; for(i = 1 ; i <= len ; i ++) { //枚举子串长度 for(j = 0 ; j <= len - i ; j ++) { strncpy(zz1, s1+j , i); zz1[i] = '\0'; //子串 //printf("%s\n",zz1); for(k = 0 ; k < i ; k ++) zz2[k] = zz1[i - k - 1]; zz2[k] = '\0'; //反转子串 //printf("%s\n",zz2); for(t = 0 ; t < n ; t ++) { if(strstr(str[t] , zz1)||strstr(str[t] , zz2)) continue; else break; } if(t == n) ans = i>ans?i:ans; } } printf("%d\n",ans); } }
后缀数组的方法:和求多串公共子串差不多的方法,不过这题要连接的不只给出的字符串,也要把给出的子串的反转串连接起来,并且loc数组的状态要和正串是一样的。
最后二分枚举最短字符串的子串长度,判断即可。
#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 21000;char str[maxn];int num[maxn] , loc[maxn];int sa[maxn] , rank[maxn] , height[maxn];int wa[maxn] , wb[maxn] , wv[maxn] , wd[maxn];int n;int cmp(int *r , int a , int b , int l) { return r[a] == r[b] && r[a+l] == r[b+l]; }void da(int *r , int n , int m) { int i , j , p; int *x = wa , *y = wb , *t; for(i = 0 ; i < m ; i ++) wd[i] = 0; for(i = 0 ; i < n ; i ++) wd[x[i]=r[i]]++; for(i = 1 ; i < m ; i ++) wd[i] += wd[i-1]; for(i = n-1 ; i >= 0 ; i --) sa[--wd[x[i]]] = i; for(j = 1 , p = 1 ; p < n ; j *= 2 , m = p) { for(p = 0 , i = n - j ; i < n ; i ++) y[p++] = i; for(i = 0 ; i < n ; i ++) if(sa[i] >= j) y[p++] = sa[i] - j; for(i = 0 ; i < n ; i ++) wv[i] = x[y[i]]; for(i = 0 ; i < m ; i ++) wd[i] = 0; for(i = 0 ; i < n ; i ++) wd[wv[i]] ++; for(i = 1 ; i < m ; i ++) wd[i] += wd[i-1]; for(i = n - 1 ; i >= 0 ; i --) sa[--wd[wv[i]]] = y[i]; for(t = x , x = y , y = t , p = 1 , x[sa[0]] = 0 , i = 1 ; i < n ; i ++) { x[sa[i]] = cmp(y , sa[i-1] , sa[i] , j) ? p - 1: p ++; } } }void calheight(int *r , int n) { int i , j , k = 0; for(i = 1 ; i <= n ; i ++) rank[sa[i]] = i; for(i = 0 ; i < n ; height[rank[i++]] = k) { for(k ? k --: 0 , j = sa[rank[i]-1] ; r[i+k]==r[j+k] ; k ++); } }int vis[1300];bool check(int mid , int len) { int i , j , cnt; cnt = 0; memset(vis , 0 , sizeof(vis)); for(i = 2 ; i <= len ; i ++) { //printf("%d\n",height[i]); if(height[i] < mid) { memset(vis,0,sizeof(vis)); cnt = 0; continue; } if(!vis[loc[sa[i-1]]]) { vis[loc[sa[i-1]]] = 1; cnt ++; } if(!vis[loc[sa[i]]]) { vis[loc[sa[i]]] = 1; cnt ++; } if(cnt == n) return 1; } return 0; }int main() { int T , i , j , g , k , temp; scanf("%d",&T); while(T--) { scanf("%d",&n); g = 0; temp = 130; int ll = 120; for(i = 0 ; i < n ; i ++) { scanf("%s",str); int len = strlen(str); if(len < ll) ll = len; for(j = 0 ; j < len ; j ++) { loc[g] = i; num[g++] = str[j]; } loc[g] = temp; num[g++] = temp++; for(j = 0 ; j < len ; j ++) { loc[g] = i; num[g++] = str[len - j - 1]; } loc[g] = temp; num[g++] = temp ++; } num[g] = 0; da(num , g+1 , temp); calheight(num , g); int left , right , mid , ans; left = 0;right = ll; while(left <= right) { mid = (left+right)/2; if(check(mid , g)) { left = mid + 1; ans = mid; } else { right = mid - 1; //ans = mid; } } printf("%d\n",ans); } }
- poj 1226 求多串最长公共子串 或 回文子串 KMP&&strstr&&后缀数组
- 【后缀数组求最长回文子串】POJ 3974
- 【后缀数组求最长公共子串】POJ 2774
- poj 2774 后缀数组 最长公共子串
- 后缀数组之最长公共子串 poj 2774
- poj 2774 最长公共子串 后缀数组
- POJ 2774 后缀数组:求最长公共子串
- poj 2774 最长公共子串 后缀数组
- poj 2217 后缀数组求最长公共子串
- poj 2774 最长公共子串(后缀数组)
- hdu1403 && poj 2774 最长公共子串 后缀数组
- POJ 2774 (最长公共子串)后缀数组+二分
- 最长公共子串--后缀数组实现
- HDU1403(后缀数组--最长公共子串)
- 最长公共子串(后缀数组)
- 最长公共子串(后缀数组)
- 【poj2774】 后缀数组最长公共子串
- 后缀数组 最长公共子串
- 如何在PL/SQL Developer中设置使其可以显示查询返回的所有记录
- webx—业务逻辑之结果集封装
- 异常的学习
- OpenGL
- 复习笔记9 if else 以及效率优化
- poj 1226 求多串最长公共子串 或 回文子串 KMP&&strstr&&后缀数组
- 一致性 hash 算法( consistent hashing )
- Web架构师成长之路
- MyEclipse6.5安装/卸载SVN插件方法
- VSTO Performance (Con'd)
- 【2012百度之星/初赛上】A:度度熊就是要第一个出场
- 1049. Brave Balloonists
- 总结Content Provider的使用
- Android NDK概览