题目:
给定两个字符串,求这两个字符串的不包含数字的最长公共子串的长度。
输入格式
共两行,每行一个由小写字母和数字构成的字符串。
输出格式
一个整数,表示给定两个字符串的不包含数字的最长公共子串的长度。
如果不存在满足要求的非空公共子串,则输出 0。
数据范围
输入字符串的长度均不超过 10000。
输入样例:
ab123abccff
abcfacb123
输出样例:
3
#include <iostream>
#include<cstring>
#include<algorithm>
#include<unordered_set>
using namespace std;
typedef unsigned long long ULL;
const int N = 20010,P=131;
int n,m;
char str[N];
ULL p[N],h[N];
ULL get(int l,int r)
{
return h[r] - h[l-1] * p[r - l + 1];//计算这一段子串的哈希值
}
bool check(int mid)
{
unordered_set<ULL> hash;
for(int i = 1; i + mid - 1 <= n; i ++ )
hash.insert(get(i,i + mid - 1));//计算a串中每一个长度为mid的子串的哈希值,并存入哈希表中
for(int i = n + 1; i + mid - 1 <= n + m; i ++)
if (hash.count(get(i, i + mid - 1)))//计算b中每一个长度为mid的子串的哈希值,并比较哈希表中的值是否有相同的,如果有,代表a串与b串有相同的mid位的子串
return true;
return false;
}
int main()
{
scanf("%s",str+1);//记录第一个串
n=strlen(str+1);
scanf("%s",str+n+1);//记录第二个串
m=strlen(str+n+1);
p[0]=1;
for(int i=1;i<=n+m;i++)
{
p[i]=p[i-1]*P;
char c = str[i];
if(isdigit(c))//若其为数字
{
if(i<=n) c = '#' ;
else c = '$';
}
h[i] = h[i - 1] * P + c;
}
int l = 0, r=min(n,m);//r为最短串的长度
while(l<r)//二分法
{
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",r);//输出子串的长度
return 0;
}
这段代码实现了一个字符串匹配算法,用于在两个字符串中寻找最长的相同子串,并输出其长度。
具体来说,该算法首先读取两个输入字符串,然后使用双指针法从最短字符串开始遍历,枚举所有可能的子串长度(使用二分查找确定长度值)。对于每个长度值,该算法会将第一个字符串中所有长度为 mid 的子串的 hash 值存入一个 unordered_set 中,并逐一查找第二个字符串中所有长度为 mid 的子串是否存在于这个 set 中。如果存在,则说明找到了相同的子串,否则继续尝试更短的子串长度。最后,该算法输出找到的最长相同子串的长度。
在实现上,该算法使用了哈希表(unordered_set)来存储子串的 hash 值,能够在常数时间内进行查找和插入操作。这样可以减少时间复杂度,并使算法更加高效。