poj1200 字符串hash

题意:求一个字符串s的所有长度为n的子串,其中原串的不同字符个数为nc.
刚开始学哈希,一直都是套的模板,用的has都是比较大的161,233等,然后都是用map用来对应的,然后一做这题就卡了,一直re或者tle。终于翻了多篇博客之后,对这题以及哈希有了更深刻的理解

思路:首先好像做题的时候忽略了一行文字,大概意思就是nc*n不超过16,000,000,这也就是之前不懂为什么是采用的nc进制,因为题目既然告诉你不同的字母只有m种,那么你就类比于10进制的方法(因为十进制不同的数不就只有10种嘛),对于字符串中出现的没有一个字母对它进行一个赋值操作,用数字作为它的键值,同时这也是为了减少数据规模。
然后这题还有个坑点就是卡map,所以你就只能自己去开一个1,000,000大小的数组,然后存储得到的哈希值。

先贴一份ac慢速(94ms)代码

#include <iostream>
#include  <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
int n, m;
const int maxn = 16000001;
char a[maxn];
bool mp[maxn];
int name[300];
int has;
ull p, h;
int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", a + 1);
    h = 0, p = 1;
    has = m;
    int len = strlen(a + 1);
    int k = 0;
    for(int i = 1; i <= len; i++) {
        if(name[a[i]] == 0) name[a[i]] = ++k;
        if(k == m) break;
    }
    int cnt = 0;
    for(int i = 1; i + n - 1 <= len; i++) {
        ull sum = 0;
        for(int j = i; j <= i + n - 1; j++) {
//            sum = sum * has + a[j];
sum=sum*has+name[a[j]];
        }
        if(!mp[sum]) {
            mp[sum] = 1;
            cnt++;
        }
    }
    printf("%d\n", cnt);
    return 0;
}

再贴一份32ms的

#include <iostream>
#include  <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
int n, m;
const int maxn = 16000001;
char a[maxn];
bool mp[maxn];
int name[300];
int has;
ull p, h;
int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", a + 1);
    h = 0, p = 1;
    has = m;
    int len = strlen(a + 1);
    int k = 0;
    for(int i = 1; i <= len; i++) {
        if(name[a[i]] == 0) name[a[i]] = ++k;
        if(k == m) break;
    }
    int cnt = 0;
    ull sum = 0;
    for(int i = 1; i <= n; i++) {
        p *= has;
        sum = sum * has + name[a[i]];
    }
    cnt++;
    mp[sum] = 1;
    for(int i = 1 + n; i <= len; i++) {

//        for(int j = i; j <= i + n - 1; j++) {
            sum = sum * has + a[j];
//            sum = sum * has + name[a[j]];
//        }
        sum = sum * has + name[a[i]] - p * name[a[i - n]];
        if(!mp[sum]) {
            mp[sum] = 1;
            cnt++;
        }
    }
    printf("%d\n", cnt);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值