字符串Hash总结模板

字符串匹配

     感觉用字符串hash 可以水过很多字符串匹配的问题,(KMP太头疼了)

实现方法:

    计算子串的hash值,在长串中从第一位开始,往后延伸到和子串同样长度,然后算出这段字符的hash值,看是否和子串的hash值相等。

题目链接

                  

模板

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 1000500

using namespace std;
typedef unsigned long long ull;
const int base=133;
ull po[maxn];
ull a[maxn],b[10005];
ull ha[maxn];

ull code(int l,int r)
{
     return ha[r]-ha[l-1]*po[r-l+1];
}
int main(void)
{
     int t,m,n;
     ull hb;
     scanf("%d",&t);
     po[0]=1;
     for(int i=1;i<maxn;i++)
     {
          po[i]=po[i-1]*base;//记得乘上相应的po值
     }
     while(t--)
     {
          memset(ha,0,sizeof(ha));
          scanf("%d%d",&n,&m);
          ha[0]=0;//如果子串的长度不是固定的不能把ha[]的值设为0,因为掩盖了长度信息
          for(int i=1;i<=n;i++)
          {
               scanf("%lu",&a[i]);
               ha[i]=ha[i-1]*base+a[i];
          }
          hb=0;
          for(int i=1;i<=m;i++)
          {
               scanf("%lu",&b[i]);
               hb=hb*base+b[i];//算出b的哈希值
          }
          int t=-1;
          for(int i=1;i<=n-m+1;i++)
          {
               if(code(i,i+m-1)==hb)
               {
                    t=i;
                    break;
               }
          }
          printf("%d\n",t);
     }
     return 0;
}

与DP结合

例题:题目链接

题目大意:

     上面串A是原文,下面的子串B表示这串字符有两个意思,问你原文可能会有多少个意思。

题目思路:

用dp[i]表示以i结尾的原文会有多少个意思,那么当以第i位结束的长度为lb=len(B)的字符串和B匹配的话,

dp[i]=dp[i-lb]+dp[i-1];①

否则dp[i]=dp[i-1]②

比如A为hehehe,B为hehe

显然我们应该从A的第四位开始循环判断,往前数4个数字(B的长度),如果和B匹配就执行①,否则执行②

至于判断是否匹配,可以用字符串哈希,相当快~

代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define maxn 100005
#define mod 1000000007

using namespace std;
typedef unsigned long long ull;
const int base=133;
ull po[maxn];
ull dp[maxn];
ull ha[maxn];
char a[maxn],b[maxn];

ull code(int l,int r)
{
     return ha[r]-ha[l-1]*po[r-l+1];
}
int main(void)
{
     int t;
     scanf("%d",&t);
     po[0]=1;
     for(int i=1;i<maxn;i++)
     {
          po[i]=po[i-1]*base;
     }
     int kase=0;
     while(t--)
     {
          memset(dp,0,sizeof(dp));
          memset(ha,0,sizeof(ha));
          //
          scanf("%s",a+1);
          scanf("%s",b+1);
          int la=strlen(a+1);int lb=strlen(b+1);
          ull hb=0;
          for(int i=1;i<=lb;i++)
          {
               hb=hb*base+b[i]-'a';//计算出b的哈希值
          }
          //开始处理a
          ha[0]=0;
          for(int i=1;i<=la;i++)
               ha[i]=ha[i-1]*base+a[i]-'a';
          //
          for(int i=0;i<lb;i++)
               dp[i]=1;
          for(int i=lb;i<=la;i++)
          {
               ull hs=code(i-lb+1,i);
               if(hs!=hb)
                    dp[i]=dp[i-1]%mod;
               else
                    dp[i]=(dp[i-lb]%mod+dp[i-1]%mod)%mod;
          }
          printf("Case #%d: %lu\n",++kase,dp[la]);
     }
     return 0;
}

呼呼

猜你喜欢

转载自blog.csdn.net/destiny1507/article/details/81544555