无名三(hash规则的特别应用)

本文深入探讨了一种基于特殊hash规则的字符串匹配算法,通过计算字符串形式的数字来高效地在目标字符串中查找模式字符串的满射。算法首先预处理模式字符串,计算其形式的数字,然后遍历目标字符串,利用相似的计算方式比较形式数字,实现快速匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于已知的字符串t,想在s中找到一个他的満射,那么我们就要在s字符串中寻找与t字符串形式相同的字符串,那么怎么样的才是形式相同的字符串呢?因此引入一个特殊的hash规则,对于t串的字符i向后找第一个与他相同的字符串的位置,他们之间的距离(如果没有相同则为1)乘该位置的xp值,那么就能得到一个代表这个形式的数字。

再从s字符串中,从头到尾枚举,每个串,应该的形式,如果相等即可。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#define MOD 1000000007
#define ll long long
using namespace std;
const int M=1e6+10;
int lens,lent;
char s[M],t[100005];
const int base=23;
int hs_t;
vector<int>to[M];
int last[25],xp[100005];
void get_t()
{
    memset(last,0,sizeof(last));
    for(int i=lent-1;i>=0;i--)
    {
        int tmp=1;
        if(last[t[i]-'a']>0)
        {
            tmp=last[t[i]-'a']-i+1;//求出t[i],i位置后面第一个i之间的距离
        }
        last[t[i]-'a']=i;
        hs_t+=tmp*xp[lent-1-i];//位置信息
    }
}
void get_to()
{
    memset(last,0,sizeof(last));
    for(int i=lens-1;i>=0;i--){
        int nxt;
        if(last[s[i]-'a']>0){
            nxt=last[s[i]-'a'];
            if(nxt-i<lent) to[nxt].push_back(i);//从nxt位置往前找第一个跟nxt字符相同的位置,在lent范围内
        }
        last[s[i]-'a']=i;
    }
}
void init(){
    xp[0]=1;
    for(int i=1;i<100005;i++)
        xp[i]=xp[i-1]*base;
}
int dis[M];
int main()
{
    scanf("%s",s);
    scanf("%s",t);
    lent=strlen(t);
    lens=strlen(s);
    if(lens<lent)return 0;
    init();
    get_t();
    get_to();

    int hs=0;
    for(int i=0;i<lens;i++)
    {
        dis[i]=1;
        hs=hs*base+1;
        if(i>=lent)hs-=dis[i-lent]*xp[lent];
        for(int j=0;j<to[i].size();j++)
        {
            int f=to[i][j];
            hs+=(i-f+1-dis[f])*xp[i-f];
            dis[f]=i-f+1;
        }
        if(i>=lent-1&&hs_t==hs)
            cout<<i-lent+2<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值