ACM暑假集训日记 17.8.9 POJ 2774 字符串 Hash

来源:互联网 发布:国投证券软件下载 编辑:程序博客网 时间:2024/06/05 19:33

十天了,算是把搜索图论专题做完了,下午看了字符串算法的Hash部分,做了个题目,poj上的,正好注册了一个poj账号,准备有空的时候刷点题,先说上午做的题目。

拓扑题,给出几个大小关系,判断是否能推出,或矛盾,或不确定;

HDU Sorting It All Out 

不是非要建立拓扑关系,借鉴思想,利用度来判断矛盾或不确定关系。

下午研究了一下Hash算法、

判断两个字符串是否相等,需要O(n)的时间,其中n为较短字符串的长度。对大量字符串,使用Hash来降低平均复杂度,最坏复杂度不会变,但最坏情况不太常见。

对于较短的字符串,可以直接储存Hash值,但是对于较长的字符串,数字会很大,即使使用unsigned long long也没办法存下,更好的方法是储存这个数对某个质数的余数,但是若采用这种方式储存,当余数不等时,原字符串一定不相等。当余数相等时,无法确定,需要对原字符串使用朴素的比较方法,因为不同数对某个数的余数可能是相等的。

对于之所以使用质数来取模,我们假设Hash表的大小为size(也就是用size取模),当size为合数,那么可以写做size=a*n;当Hash的值为Hashnow=b*n时,则取模后

Hashnow=Hashnow mod size

               =Hashnow-(Hashnow / size) * size;

               =Hashnow-(b/a)* size;

因为a是固定的,那么Hashnow的值就有b种情况,显然更容易出现不确定情况。

Hash算法实现:

pow[0]=1;

for(int i=1;i<=ls;i++)

     pow[i]=(pow[i-1]*num)%mod               //计算基数的幂次,节约以后的运算时间,num可以看做是进制  

hash[0]=0;

for(int i=0;i<ls;i++)

     hash[i+1]=(hash[i]*num+s[i])%mod;    //计算s的每一个前缀的hash值

//在main函数中,要对数组 pow,hash赋初值

int gethash(int h[],int i,int j)                       //得到[i,j)区间内的子串Hash值

{

      int tmp=(h[j]-h[i]*pow[j-i])%mod;

      if(tmp<0)return tmp+mod;

      else return tmp;

}

bool equal(char s1[],char s2[],int n)          //朴素方法得到长度为n的两个子串是否相等

{

      for(int i=0;i<n;i++)

           if(s1[k]!=s2[k])return 0;

      return 1;

}

做了一个练习题 POJ 2774

看原题

AC代码

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int N=100001;
int ls1,ls2;
char s1[N],s2[N];
unsigned long long hash1[N],hash2[N],pow[N],a[N];
inline unsigned long long gethash(unsigned long long h[],int i,int j)
{
    return h[j]-h[i]*pow[j-i];
}
int havesolution(int t)
{
    int n=0;
    for(int i=t;i<=ls1;i++)
        a[n++]=gethash(hash1,i-t,i);
    sort(a,a+n);                                                //必须进行排列,binary_search使用前提需要是已排序的
    for(int i=t;i<=ls2;i++)
    {
        unsigned long long w=gethash(hash2,i-t,i);
        if(binary_search(a,a+n,w))
        return 1;
    }
    return 0;
}
int main()
{
    scanf("%s",s1);
    scanf("%s",s2);
    ls1=strlen(s1);
    ls2=strlen(s2);
    int l=0,r=max(ls1,ls2);
    pow[0]=1;
    for(int i=1;i<=r;i++)
        pow[i]=pow[i-1]*27;
    hash1[0]=0;


    for(int i=0;i<ls1;i++)
        hash1[i+1]=(hash1[i]*27+s1[i]-'a');          //应该是可以看做26进制,但是用26提交了一次error了,改成27才对
    for(int i=0;i<ls2;i++)
        hash2[i+1]=(hash2[i]*27+s2[i]-'a');
    while(l!=r)
    {
        int t=(l+r)/2;
        if(havesolution(t+1))l=t+1;
        else r=t;
    }
    printf("%d\n",l);
    return 0;
}

原创粉丝点击