HDU2087 剪花布条 [Hash]

1 篇文章 0 订阅

HDU2087 剪花布条 \text{HDU2087 剪花布条} HDU2087 剪花布条

典型的字符串匹配问题。

网上KMP的解法太多了,我就来一发Hash哈希算法吧。

预处理:

    Power[0]=1;
    for(register int i=1;i<=1000;i++)
        Power[i]=Power[i-1]*Base%mod;

先预先算出 B 1 − B 1001 B^{1}-B^{1001} B1B1001的值,在Hash的过程会方便一些。(B是基数,此处取1000007)

主串Hash
inline void Init(int len)
{
    Hash[0]=0;
    register int i;
    for(i=1;i<=len;i++)
        Hash[i]=(Hash[i-1]*Base%mod+(Main[i]-'A'+1)%mod)%mod;
    return;
}

Hash[i]主串 1 − i 1-i 1i位的Hash值。

我们通过这个公式计算哈希值: H ( C [ 1... i ] ) = ( H ( C [ 1... i − 1 ] ∗ B + C i ) ) H(C[1...i])=(H(C[1...i-1]*B+C_i)) H(C[1...i])=(H(C[1...i1]B+Ci))
H ( C ) = ( C 1 × B n + C 2 × B n − 1 + . . . + C n × B ) H(C)=(C_1\times B^n+C_2\times B^{n-1}+...+C^n\times B) H(C)=(C1×Bn+C2×Bn1+...+Cn×B)

获取主串中部分的Hash值
inline ull Get_Hash(int L,int R)
{
    return Hash[R]%mod-Hash[L-1]*Power[R-L+1]%mod;
}

根据Hash的公式,截取主串中 L . . R L..R L..R的Hash值。
如此不断右移,对比Hash值,就可以知道字符串匹配了。

完整代码:

#include<cstdio>
#include<cstring>
using namespace std;

typedef long long ull;
const int Base=1000007;
const int mod=1e9+7;
ull Power[1001];
ull Hash[1001];
char Main[1001],Model[1001];

inline void Init(int len)
{
    Hash[0]=0;
    register int i;
    for(i=1;i<=len;i++)
        Hash[i]=(Hash[i-1]*Base%mod+(Main[i]-'A'+1)%mod)%mod;
    return;
}

inline ull Get_Hash(int L,int R)
{
    return Hash[R]%mod-Hash[L-1]*Power[R-L+1]%mod;
}

inline int Count()
{
    register int i;
    int len1=strlen(Main+1);
    int len2=strlen(Model+1);
    ull H_model=0;
    Init(len1);
    int result=0;
    for(i=1;i<=len2;i++)
        H_model=(H_model*Base%mod+(Model[i]-'A'+1)%mod)%mod;
    for(i=1;i<=len1-len2+1;i++)
        if(H_model==Get_Hash(i,i+len2-1))
            result++,i+=len2-1;//不能重复!!!
    return result;
}

int main()
{
    Power[0]=1;
    for(register int i=1;i<=1000;i++)
        Power[i]=Power[i-1]*Base%mod;
    while(scanf("%s",Main+1)&&Main[1]!='#')
    {
        scanf("%s",Model+1);
        printf("%d\n",Count());
    }
    return 0;
}

At last:

puts("点个赞吧!");
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值