zoukankan      html  css  js  c++  java
  • 【字符串匹配】【BKDRhash||KMP】

    题目描述
    给定一个字符串 A 和一个字符串 B ,求 B 在 A 中的出现次数。A 和 B中的字符均为英语大写字母或小写字母。 A 中不同位置出现的 B 可重叠。
    
    输入格式
    输入共两行,分别是字符串 A 和字符串 B 。
    
    输出格式
    输出一个整数,表示 B 在 A 中的出现次数。
    
    样例一
    input
    
    zyzyzyz
    zyz
    output
    
    3
    限制与约定
    对于100%的数据:1≤A,B的长度≤106,A、B仅包含大小写字母。1≤A,B的长度≤106,A、B仅包含大小写字母。
    时间限制:1s1s
    空间限制:256MB256MB
    T

    这道题题意很简单,是字符串hs和KMP的裸题

    字符串hs是一个准确率不是100%的算法,它的做法略玄学

    就是把一个字符串按ASC码用一个进制(也叫seed,通常是131,13131)转成一个数字,并且使用unsigned long long自然溢出,

    匹配时用小串的一部分和大串的一部分对比hs值实现匹配

    代码如下

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define N 1000055
     5 #define seed 13131
     6 using namespace std;
     7 typedef unsigned long long ull;
     8 char a[N],b[N];
     9 int alen,blen;
    10 long long cnt;
    11 ull se[N],aa,abc[N];
    12 inline void init()
    13 {
    14     scanf("%s%s",a+1,b+1);
    15     se[0]=1;
    16     alen=strlen(a+1),blen=strlen(b+1);
    17     for(int i=1;i<=alen;i++)
    18         se[i]=se[i-1]*seed,
    19         abc[i]=abc[i-1]*seed+(a[i]-'0');
    20     for(int i=1;i<=blen;i++)
    21         aa=aa*seed+(b[i]-'0');
    22 }
    23 int main()
    24 {
    25     init();
    26     for(int i=1;i+blen-1<=alen;i++)
    27     {
    28         int l=i,r=l+blen-1;
    29         if(aa==abc[r]-abc[l-1]*se[r-l+1])cnt++;
    30     }
    31     printf("%lld
    ",cnt);
    32     return 0;
    33 }

    然后是一种绝对准确,但是会比hs慢的算法,它叫KMP,名字取自三位大佬的名字的首字母

    思想就是在失配时候不是调到头,而是利用之前的信息,跳到一个更佳的位置,从而节约时间复杂度

    nxt数组的求法是算法的精髓

     1 void getnxt()
     2 {
     3     int k=0,j=1;
     4     nxt[1]=0;
     5     while(j<=plen)
     6     {
     7         if(k==0||p[j]==p[k])
     8             k++,j++,nxt[j]=k;
     9         else
    10             k=nxt[k];
    11     }
    12 }

    我习惯右移一位存储所以和网上的代码不太一样

    网上很多讲解,不再赘述

    那里的nxt[1]=0是最神奇的地方,用手模拟一下会发现当第一位失配时候,这么做就可以巧妙的解决

    求的时候这么求

     1 int solvebyKMP()
     2 {
     3     int pt=1,pp=1,fin=0;
     4     while(pt<=tlen)
     5     {
     6         if(t[pt]==p[pp]||pp==0)
     7             pt++,pp++;
     8         else pp=nxt[pp];
     9         if(pp==plen+1)fin++,pp=nxt[pp];
    10     }
    11     return fin;
    12 }

    然后就能解决,

    关于nxt数组的应用还有很多,以后的博客中会讲到

     1 #include<cstdio>
     2 #include<cstring>
     3 #define N 1000111
     4 #define clear(a,val) memset(a,val,sizeof(a))
     5 using namespace std;
     6 char t[N],p[N];
     7 int tlen,plen;
     8 int nxt[N];
     9 void getnxt()
    10 {
    11     int k=0,j=1;
    12     nxt[1]=0;
    13     while(j<=plen)
    14     {
    15         if(k==0||p[j]==p[k])
    16             k++,j++,nxt[j]=k;
    17         else
    18             k=nxt[k];
    19     }
    20 }
    21 int solvebyKMP()
    22 {
    23     int pt=1,pp=1,fin=0;
    24     while(pt<=tlen)
    25     {
    26         if(t[pt]==p[pp]||pp==0)
    27             pt++,pp++;
    28         else pp=nxt[pp];
    29         if(pp==plen+1)fin++,pp=nxt[pp];
    30     }
    31     return fin;
    32 }
    33 int main()
    34 {
    35     scanf("%s%s",t+1,p+1);
    36     tlen=strlen(t+1),plen=strlen(p+1); 
    37     getnxt();
    38     printf("%d",solvebyKMP());    
    39     return 0;
    40 }
  • 相关阅读:
    构造方法
    构造方法的重载
    封装的使用及演示代码
    static的用法及作用
    javaWeb链接数据库进行增删改查
    java面向对象接口小结
    多线程总结
    mysql数据查询
    mysql条件查询
    mysql查询数据
  • 原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10204339.html
Copyright © 2011-2022 走看看