POJ1226 Substrings ——后缀数组 or 暴力+strstr()函数 最长公共子串

时间:2025-05-07 14:33:38

题目链接:https://vjudge.net/problem/POJ-1226

Substrings
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 15122   Accepted: 5309

Description

You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.

Input

The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.

Output

There should be one line per test case containing the length of the largest string found.

Sample Input

2
3
ABCD
BCDFF
BRCD
2
rose
orchid

Sample Output

2
2

Source

题意:

给出n个字符串,问是否存在一个公共子串存在于每个字符串或其逆串中,若存在,输出最长的长度。

题解:

1.将所有字符串已经其逆串拼接在一起,相邻两个之间用各异的分隔符隔开。

2.求出新串的后缀数组,然后二分公共子串的长度mid:mid将新串的后缀分成若干组,每一组对应着一个公共子串,并且长度>=mid。如果这组出现了所有字符串,那么说明当前mid合法,否则不合法。最终求得答案。

3.由于数据较弱,还可以直接暴力+kmp/strstr()函数。

后缀数组:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5+; int id[MAXN];
int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
int t1[MAXN], t2[MAXN], c[MAXN]; bool cmp(int *r, int a, int b, int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
} void DA(int str[], int sa[], int Rank[], int height[], int n, int m)
{
n++;
int i, j, p, *x = t1, *y = t2;
for(i = ; i<m; i++) c[i] = ;
for(i = ; i<n; i++) c[x[i] = str[i]]++;
for(i = ; i<m; i++) c[i] += c[i-];
for(i = n-; i>=; i--) sa[--c[x[i]]] = i;
for(j = ; j<=n; j <<= )
{
p = ;
for(i = n-j; i<n; i++) y[p++] = i;
for(i = ; i<n; i++) if(sa[i]>=j) y[p++] = sa[i]-j; for(i = ; i<m; i++) c[i] = ;
for(i = ; i<n; i++) c[x[y[i]]]++;
for(i = ; i<m; i++) c[i] += c[i-];
for(i = n-; i>=; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y);
p = ; x[sa[]] = ;
for(i = ; i<n; i++)
x[sa[i]] = cmp(y, sa[i-], sa[i], j)?p-:p++; if(p>=n) break;
m = p;
} int k = ;
n--;
for(i = ; i<=n; i++) Rank[sa[i]] = i;
for(i = ; i<n; i++)
{
if(k) k--;
j = sa[Rank[i]-];
while(str[i+k]==str[j+k]) k++;
height[Rank[i]] = k;
}
} bool vis[];
bool test(int n, int len, int k)
{
int cnt = ;
memset(vis, false, sizeof(vis));
for(int i = ; i<=len; i++)
{
if(height[i]<k)
{
cnt = ;
memset(vis, false, sizeof(vis));
}
else
{
if(!vis[id[sa[i-]]]) vis[id[sa[i-]]] = true, cnt++;
if(!vis[id[sa[i]]]) vis[id[sa[i]]] = true, cnt++;
if(cnt==n) return true;
}
}
return false;
} char str[MAXN];
int main()
{
int T, n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int len = ;
for(int i = ; i<n; i++)
{
scanf("%s", str);
int LEN = strlen(str);
for(int j = ; j<LEN; j++)
{
r[len] = str[j];
id[len++] = i;
}
r[len] = +i; //分隔符
id[len++] = i;
}
for(int i = ; i<len; i++) //逆串
{
r[*len--i] = r[i];
if(r[*len--i]>=) r[*len--i] += ; //分隔符应各异
id[*len--i] = id[i];
}
len *= ;
r[len] = ;
DA(r,sa,Rank,height,len,); int l = , r = ;
while(l<=r)
{
int mid = (l+r)>>;
if(test(n,len,mid))
l = mid + ;
else
r = mid - ;
}
printf("%d\n", r);
}
}

暴力 + strstr()函数:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
typedef long long LL;
const double eps = 1e-;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = +; char s[MAXN][MAXN], t1[MAXN], t2[MAXN]; int main()
{
int T, n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = ; i<=n; i++)
scanf("%s", s[i]); int Len = strlen(s[]), ans = ;
for(int len = Len; len>=; len--)
{
for(int st = ; st<=Len-len; st++)
{
int en = st+len-, cnt = ;
for(int i = st; i<=en; i++)
{
t1[cnt] = s[][i];
t2[cnt++] = s[][i];
}
t1[cnt] = t2[cnt] = ;
reverse(t2,t2+cnt); bool flag = true;
for(int i = ; i<=n; i++)
flag = flag&&(strstr(s[i], t1) || strstr(s[i], t2) ); if(flag)
{
ans = len;
break;
}
}
if(ans==len) break;
}
printf("%d\n", ans);
}
}