【ACWing 每日一练之最长公共子串 】

这段代码实现了一个字符串匹配算法,通过哈希和二分查找在两个字符串中寻找最长的相同子串。算法首先读取两个字符串,然后使用哈希表存储第一个字符串的子串hash值,并检查第二个字符串的子串是否存在相同的hash值,最终输出最长相同子串的长度。
摘要由CSDN通过智能技术生成

题目:

给定两个字符串,求这两个字符串的不包含数字的最长公共子串的长度。

输入格式

共两行,每行一个由小写字母和数字构成的字符串。

输出格式

一个整数,表示给定两个字符串的不包含数字的最长公共子串的长度。

如果不存在满足要求的非空公共子串,则输出 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 值,能够在常数时间内进行查找和插入操作。这样可以减少时间复杂度,并使算法更加高效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值