zoukankan      html  css  js  c++  java
  • 哈希Hash在字符串中的应用_C++

      本文含有原创题,涉及版权利益问题,严禁转载,违者追究法律责任

      哈希大家都会用撒,字符串显然都会写撒,那么哈希离散化字符串不就懂了?!(XXX的神逻辑,其实原文是:树都晓得吧,数组显然都会开呀,那么恭喜你学会了树状数组!)

      例如我们给出 n 个长度为 m 的字符串,然后给你一个长度为 m 的字符串 s ,求 s 是否在之前的 n 个串中出现过

      暴力扫 n 个串,然后一位位去对,看是否相等,时间复杂度O(nm),它非常得辣鸡

      当然我们可以建一颗 trie 树做,但是建树的复杂度也是O(nm)的,对于只询问一次还不如打暴力

      一阵思考后,我们选用非常优秀的哈希(以下简称Hash)

      (机制的人请忽略这篇文章)

      平常我们用 Hash 是对数字进行处理,一般把它取模之后离散化到各个数组

      但是对于字符串呢?难道把它所有位加起来取模?显然是不行的,如 ab 和 ba 这两种情况是相同的,那么小节点挂的链会很多

      于是乎,我们想,对于字符串只有256种,而题目中给的一般只会包含字母,甚至是只有小写字母,瞬间压缩到26种

      那么我们可以把它前面 k 位取出来,如取4位出来是 axoc,把它装换成对应的数字是 0 23 14 2 (a 看做 0,b 看做 1 …… z 看做 25)

      这不就是一个二十六进制数!

      把前 k 位取出来,第 i 位即为这个26进制数的第 i 位,再把它转换为10进制,如 axoc 为 45214,这样我们就得到了 Hash 的 Hash 函数了

      字符串判重就容易了, Hash 具体实现过程就不用讲了吧

      对于 26 进制的数,int 范围下只能取到第 6 位,long long范围下可以取到第 13 位

        

      下面给道例题

      题意很简单,给你一个串,求他有多少个不同的子串,满足前缀为A,后缀为B。 需要注意的是,串中所有的字母都是小写字母。

      三个串长度均小于等于 2000,时间1s,空间128MB

      样例输入:abababab

           a

           b

      样例输出:4

      直接暴力枚举然后 Hash 判重,我们这里截取前3位做 Hash 函数

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 
      9 const int N=11000,loc=3,power[8]={0,1,26,676,17576,456976,11881376,308915776},mo=17576;
     10 struct Hash
     11 {
     12     int next;
     13     char s[N];
     14 }
     15     hs[N*2];
     16 char a[N],b[N],s[N];
     17 int ls,ans,next[N],f[N],top,first[mo],tg,g[mo];
     18 bool fa[N],fb[N];
     19 void init(char c[N],int len)
     20 {
     21     int i,j=0;
     22     for (i=1;i<len;i++)
     23     {
     24         while (j&&c[i]!=c[j]) j=next[j];
     25         if (c[i]==c[j]) j++;
     26         next[i+1]=j;
     27     }
     28 }
     29 void kmp(char c[N],int len)
     30 {
     31     int i,j=0;
     32     top=0;
     33     for (i=0;i<=len;i++) next[i]=0;
     34     init(c,len);
     35     for (i=0;i<ls;i++)
     36     {
     37         while (j&&s[i]!=c[j]) j=next[j];
     38         if (s[i]==c[j]) j++;
     39         if (j==len)
     40         {
     41             f[++top]=i-j+1;
     42             j=next[j];
     43         }
     44     }
     45 }
     46 void hash(char c[N],int len)
     47 {
     48     int i,x=0,t=min(len,loc);
     49     for (i=1;i<=t;i++) x+=(c[i]-'a')*power[i];
     50     if (first[x]) for (i=first[x];i;i=hs[i].next)
     51     {
     52         t=len-loc;
     53         if (t<=0) return;
     54         for (x=1;x<=t;x++) if (hs[i].s[x]!=c[loc+x]) break;
     55         if (x>t) return;
     56     }
     57     if (!(hs[++top].next=first[x])) g[++tg]=x;
     58     first[x]=top;
     59     x=0;
     60     for (i=loc+1;i<=len;i++) hs[top].s[++x]=c[i];
     61     ans++;
     62 }
     63 int main()
     64 {
     65     int la,lb,i,j,t,x,k,l;
     66     char c[N];
     67     scanf("%s
    %s
    %s
    ",&s,&a,&b);
     68     ls=strlen(s);
     69     la=strlen(a);
     70     lb=strlen(b);
     71     kmp(a,la);
     72     for (i=1;i<=top;i++) fa[f[i]]=1;
     73     kmp(b,lb);
     74     for (i=1;i<=top;i++) fb[f[i]]=1;
     75     t=ls-la-lb;
     76     for (j=1;j<=t;j++)
     77     {
     78         for (i=1;i<=tg;i++) first[g[i]]=0;
     79         top=tg=0;
     80         for (i=0;i<=t-j;i++)
     81         {
     82             x=i+j+la;
     83             if (fa[i]&&fb[x])
     84             {
     85                 l=0;
     86                 for (k=i+la;k<x;k++) c[++l]=s[k];
     87                 hash(c,j);
     88             }
     89         }
     90     }
     91     for (i=max(la-lb-1,0);i<=la;i++)
     92     {
     93         j=i;
     94         while (a[j]==b[j-i]) j++;
     95         if (a[j]!='') continue;
     96         for (j=0;j<i;j++) c[j]=a[j];
     97         for (k=0;k<lb;k++,j++) c[j]=b[k];
     98         kmp(c,j);
     99         if (top) ans++;
    100     }
    101     printf("%d
    ",ans);
    102     return 0;
    103 }

      据说可以用KMP或者EXKMP做orz

      还有我的程序在 Hash 取别的位数的时候会 WA 几个点(而且还是不同的点??)

      求助大神能解释一下orz(再次体现我的蒟蒻)

      注:该题为原创题,可购买数据,价格 RMB 2.0

      如需购买在这 Get 联系方式  http://www.cnblogs.com/hadilo/p/5932395.html

  • 相关阅读:
    导出excel
    织梦dedecms内页分类频道友情链接实现方法
    织梦dedecms首页/列表页/内容页调用tag的方法(未测试)
    织梦CMS首页、列表页文章如何调出该文章TAG标签?
    JS点击查看更多内容 控制段落文字展开折叠
    dedecms自定义表单提交成功如何返回当前页面
    织梦菜单导航调用特定栏目
    DEDE自定义表单显示提交时间|添加提交时间,获取ip的方法
    DEDECMS织梦自定义表单中必填项、电话邮箱过滤以及验证码规则
    织梦怎么创建新的内容模型?
  • 原文地址:https://www.cnblogs.com/hadilo/p/5932474.html
Copyright © 2011-2022 走看看