题目描述
给定n个串,m次询问,每次询问两个串的lcp(最长公共前缀)
输入格式
第一行包含两个数n,m,表示n个串,m次询问。
接下来n行,每行一个串。
再接下来m行,每行两个整数a,b表示询问编号为a和b的两个串的lcp。
输出格式
输出包含m行,即为询问的答案
样例一
input
5 3
except
expert
expect
example
exam
1 2
2 3
4 5
output
2
4
4
限制与约定
对于30%30%的数据,m≤103,m≤103,每个串的长度 ≤103≤103;
对于100%100%的数据,n≤103,m≤105,n≤103,m≤105,每个串的长度 ≤104≤104.
时间限制:1s
空间限制:512MB
思路:
对于两个字符串的公共前缀,它们的每一位哈希值都是相等的
则在两个字符串中,满足在最后一位公共前缀前,每位哈希值相等;公共前缀后,哈希值不等
故可将两字符串看做有序表,进行折半查找最后一位公共前缀的位置。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int DI = 29;//大于字符种数
const int MAXN = 1000 + 5;
const int MAXL = 10000 + 5;
char a[MAXL];
int n,m,chang[50005];
unsigned long long hs[1005][10005];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
{
memset(a,0,sizeof(a));
scanf("%s",a + 1);
int len = strlen(a + 1);
chang[i] = len;
for(int j = 1;j <= len;j ++)
{
hs[i][j] = hs[i][j - 1] * DI + (a[j] - 'a' + 1);
}
}
int x,y,L,R,mid;
for(int i = 1;i <= m;i ++)
{
scanf("%d%d",&x,&y);
if(chang[x] > chang[y])
swap(x,y);
L = 0,R = chang[y] + 1;//右边界不可任意,否则每一位哈希为0;
//公共前缀最长为最最短串的长度,因R始终指向不合法,所以将最短串长度 + 1设为右边界
while(R - L > 1)
{
mid = R + L >> 1;
if(hs[x][mid] == hs[y][mid])//mid为公共前缀某一位
{
L = mid;//L始终合法
}
else
{
R = mid;//R始终不合法
}
}
printf("%d\n",L);//答案输出L
}
return 0;
}

本文介绍了一种基于哈希和二分查找的高效算法来解决字符串的最长公共前缀(LCP)查询问题。该算法适用于多个字符串之间的LCP批量查询场景,通过预处理字符串哈希值,可以在较短时间内确定任意两个字符串间的最长公共前缀长度。
1792

被折叠的 条评论
为什么被折叠?



