Hash——字符串匹配(求s1在s2中出现的次数)

题目描述:

这是一道模板题。

给定一个字符串 A 和一个字符串 B ,求 B 在 A  中的出现次数。A 和 B中的字符均为英语大写字母。

求A 在 B 中出现了几次。(可重叠)

样例输入:

3

BAPC

BAPC

AZA

AZAZAZA

VERDI

AVERDXIVYERDIAN

样例输出:

1

3

0

首先要知道什么是字符串hash(滚动哈希):

  单哈希可以O(m)的时间计算长度为m的字符串的哈希值,但对于本题,总的时间复杂度没有改观。时间会爆。

  这时我们就需要一个叫做滚动哈希的优化技巧。

  我们选取两个合适的互质常数b和h(b<h),假设字符串C=c1c2……cm,那么我们定义哈希函数:H(C)=(c1bm-1+c2bm-2+……+cmb0) mod h 。

  正常数字是十进制的,这里b是基数,相当于把字符串看做是b进制数。

  这一过程是递推计算的,设H(C,k)为前k个字符构成的字符串的哈希值,则:(以下均不考虑取模的情况)

  H(C,k+1)=H(C,k)× b + ck+1

  字符串哈希,通常题目要求的是判断主串的一段字符串与另一个匹配串是否匹配,即判断字符C=c1c2……cm从位置k+1开始的长度为n的子串C‘=ck+1ck+2……ck+n的哈希值与另一匹配串S=s1s2……sn的哈希值是否相等,则:

  H(C‘)=H(C,k+n) - H(C,k) × bn

  于是我们只要预求得b,就能在O(1)时间内得到任意字符串的字符串的子串哈希值,从而完成字符串匹配,那么上述字符串匹配问题的算法复杂度就为O(n+m)。

  在实现算法时,可以利用32位或64位无符号整数计算hash值(如:unsigned long long),并取h=232或h=264,通过子让溢出省去取模运算。

                                                                              ——By《一本通》

那么本题就可以用上述方式AC了(书上代码有bug,需自己改动)

  代码如下:

#include<cstdio>
#include<cstring>
using namespace std;
#define ULL unsigned long long
#define K 103
int N;
char s1[1000005], s2[1000005];
ULL f[1000005],l1,l2,t;
ULL a[1000005];
ULL get(int x,int y)
{
    return f[y]-f[x-1]*a[y-x+1];
}
int main()
{
    //freopen("字符串匹配(求s1在s2中出现的次数).in","r",stdin);
    //freopen("字符串匹配(求s1在s2中出现的次数).out","w",stdout);
    scanf("%d",&N);
    a[0]=1;
    for(int i=1;i<=1000000;++i)//预处理出a^n
        a[i]=a[i-1]*K;
    for(int i=1;i<=N;++i)
    {
        int ans(0);t=0;
        scanf("%s%s",s2+1,s1+1);
        l1=strlen(s1+1);l2=strlen(s2+1);
        for(int j=1;j<=l1;++j)
            f[j]=f[j-1]*K+(s1[j]-‘A‘);//计算主串的滚动哈希值
        for(int j=1;j<=l2;++j)
            t=t*K+(s2[j]-‘A‘);//计算匹配串的哈希值
        for (int j=1;j+l2-1<=l1;++j)
        {
            if(get(j,j+l2-1)==t)//枚举起点为i,长度为n的子串,判断与匹配串是否匹配
                ans++;
        }
        printf("%d\n",ans);//输出
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lck-lck/p/9588740.html

时间: 2024-10-28 17:24:48

Hash——字符串匹配(求s1在s2中出现的次数)的相关文章

OJ题目:字符串匹配求指点

kogioi奖凰豢形慌材<http://weibo.com/20180414p/230927983085792249257984> iiauua俳炕案沼芬喂<http://weibo.com/p978p478p/230927983067083371712512> o6skc2暇任撂啦乘闻<http://weibo.com/p20180414p/230927983037668214444032?z1> qscm8c呛颇佑烁橇狼<http://weibo.com/kq

JAVA常见算法题(三十三)---求子串在字符串中出现的次数

计算某字符串中子串出现的次数. public static void main(String[] args) { String s1 = "adcdcjncdfbcdcdcd"; String s2 = "cd"; count(s1, s2); } public static void count(String str1, String str2) { int count = 0; if (str1.equals("") || str2.equa

hdoj 4552 怪盗基德的挑战书【求前缀在字符串中出现的次数之和】

怪盗基德的挑战书 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 990    Accepted Submission(s): 478 Problem Description “在树最美丽的那天,当时间老人再次把大钟平均分开时,我会降临在灯火之城的金字塔前,带走那最珍贵的笑容.”这是怪盗基德盗取巴黎卢浮宫的<蒙娜丽莎的微笑>这幅画时,挑

将字符串s1中的任何与字符串s2中字符匹配的字符都删除

编写一个程序,将字符串s1中的任何与字符串s2中字符匹配的字符都删除. 函数原型:void my_squeeze(char s1[], char s2[]) #include <stdio.h> void my_squeeze(char s1[], char s2[]) { int i = 0; int j = 0; while (s2[j]) { while(s1[i]) { if (s2[j]==s1[i]) { while (s1[i+1]) { s1[i] = s1[i + 1]; i

squeeze(s1,s2),将字符串s1中任何与字符串s2中匹配的字符都删除

void squeeze(char a[],char b[]) { //要实现把s2的任意字符如果出现的话就在s1中删除 //1.首先判断s1[j]==s2[i]&&s1[j]=='\0' int j,i; for( j=0;b[j]!='\0';j++)//遍历一遍b[] { for(i=0;a[i]!='\0';i++)//遍历一遍a { if(a[i]==b[j]) for(int m=i;(a[m]=a[1+m])!='\0';m++);//消除元素 } } } //其实里面那些{

字符串匹配(hash算法)

hash函数对大家来说不陌生吧 ? 而这次我们就用hash函数来实现字符串匹配. 首先我们会想一下二进制数. 对于任意一个二进制数,我们将它化为10进制的数的方法如下(以二进制数1101101为例): hash用的也是一样的原理,为每一个前缀(也可以后缀,笔者习惯1 base,所以喜欢用前缀来计算,Hash[i] = Hash[i - 1] * x + s[i](其中1 < i <= n,Hash[0] = 0). 一般地, 而对于l - r区间的hash值,则为: 但是如果n很大呢?那样不是

java实现字符串匹配问题之求两个字符串的最大公共子串

转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/38924981 近期在项目工作中有一个关于文本对照的需求,经过这段时间的学习,总结了这篇博客内容:求两个字符串的最大公共子串. 算法思想:基于图计算两字符串的公共子串.详细算法思想參照下图: 输入字符串S1:achmacmh    输入字符串S2:macham 1)第a步,是将字符串s1,s2分别按字节拆分,构成一个二维数组: 2)二维数组中的值如b所看到的,比方第一行第一列的值

java实现字符串匹配问题之求最大公共子串

转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/38924981 最近在项目工作中有一个关于文本对比的需求,经过这段时间的学习,总结了这篇博客内容:求两个字符串的最大公共子串. 算法思想:基于图计算两字符串的公共子串.具体算法思想参照下图: 输入字符串S1:achmacmh    输入字符串S2:macham 1)第a步,是将字符串s1,s2分别按字节拆分,构成一个二维数组: 2)二维数组中的值如b所示,比如第一行第一列的值表示

时空权衡之字符串匹配中的输入增强技术

字符串匹配的蛮力的算法: 对于字符数为n的文本,模式(要匹配的字符串)字符为m的字符串,简单的从左到右比较模式和文本中每一对相应的字符,,如果不匹配,模式向右移一格,再进行下一轮的尝试. 这样尝试的最大次数为n-m+1次,模式进行m次比较,这样比较次数一共是m(n-m+1)=O(nm),次,对于随机的自然文本,它的平均效率为O(n+m) 使用输入增强的思想:对模式进行预处理以得到它的一些信息,把这些信息储存在表中,然后在给定文本中实际查找模式时使用这些信息. 以下是这种思维下的两种算法: 一.H