现在的位置: 首页 > 算法 > 正文

poj 1200 || zoj 1507 Crazy Search (Hash表)

2018年09月22日 算法 ⁄ 共 969字 ⁄ 字号 评论关闭

题目链接:   http://poj.org/problem?id=1200

题目大意:  给出两个数字N和NC,一行字符串

                    这行字符串最多出现NC个字符

                    寻找长度为N的不同子串个数

解题思路:   字符串的长度最长为1600万,用strcmp()函数判断次数太多,肯定会TLE

                    开始用了BKDRHask,和ELFHask都WA,说明有些字串的hash值相等

                    为了避免这种情况我用链表来处理冲突,但是爆内存了,原因是数组太大!

                    最后把问题转化成NC进制,AC了

                    这道题可以用一个很巧妙的方法,将数值降到最小:

           如:

                    3 3

                    abcabc

                    abc:1x3^2+2x3^1+3x3^0=18

                    bca:2x3^2+3x3^1+1x3^0=28

                    cab:3x3^2+1x3^1+2x3^0=32

                    abc:1x3^2+2x3^1+3x3^0=18

                    3

代码:

//hash基础题, 转化为 nc进制
#include <stdio.h>
#include <string.h>
#define MAX 1600000
char ch[MAX];
int Hash[MAX*10]={0},a[256]={0};
int main()
{
    int i,j,h,t,n,nc,num;
    scanf("%d%d%s",&n,&nc,ch);
    memset(a,-1,sizeof(a));
    for(i=0;ch[i]!='\0';i++)
    {
        if(a[ch[i]]==-1)
        {
            a[ch[i]]=1;
        }
    }
    for(i=0,num=0;i<256;i++)
    {
        if(a[i]!=-1)
            a[i]=num++;     //***减少数的大小,防止数组不够大,从0开始!
    }
    for(i=0,t=0;ch[i+n-1]!='\0';i++)
    {
        h=0;
        for(j=i;j<i+n;j++)
        {
            h=h*nc+a[ch[j]];
        }
        if(!Hash[h])  //判断之前是否存在
        {
            Hash[h]=1;
            t++;    //新加入的标记
        }
    }
    printf("%d\n",t);
    return 0;
}

注:原创文章,转载请注明出处

抱歉!评论已关闭.