字符串哈希

概念

  • 将字符串通过一个哈希函数转换为哈希值,作为这个字符串的唯一标识。
  • 主要作用是加速判断两个字符串是否相等

实现方法

  • 采用高进制,每个字符对应相应位上的一个数字,这样就将字符串转换为一个巨大的整数
  • 然而这样并不能加速对两字符串的比较
  • 通过对一个大质数取模作为哈希值,这样可以极大加速判断但存在出错的风险(两个不同的字符串哈希值相同)
  • 实际判断时可以同时先比较字符串长度等降低出现哈希值相同导致判断出错的概率

哈希函数

int prime = 233317, base=131;
ull mod = 212370440130137957;
ull hashe(char s[]) {
	int len = strlen(s);
	ull ans = 0;
        // 关键
	for (int i = 0; i < len; i++) 
        // 减小重复概率
        ans = (ans * base + ull(s[i])) % mod + prime;
	return ans;
}

P3370 【模板】字符串哈希

题目描述

如题,给定 NN 个字符串(第 ii 个字符串长度为 M_iM**i,字符串内包含数字、大小写字母,大小写敏感),请求出 NN 个字符串中共有多少个不同的字符串。

#友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:)

输入格式

第一行包含一个整数 NN,为字符串的个数。

接下来 NN 行每行包含一个字符串,为所提供的字符串。

输出格式

输出包含一行,包含一个整数,为不同的字符串个数。

输入输出样例

输入 #1复制

5 abc aaaa abc abcc 12345

输出 #1复制

4

说明/提示

对于 30%30% 的数据:N\leq 10N≤10,M_i≈6M**i≈6,Mmax\leq 15Mma**x≤15。

对于 70%70% 的数据:N\leq 1000N≤1000,M_i≈100M**i≈100,Mmax\leq 150Mma**x≤150。

对于 100%100% 的数据:N\leq 10000N≤10000,M_i≈1000M**i≈1000,Mmax\leq 1500Mma**x≤1500。

样例说明:

样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。

Tip: 感兴趣的话,你们可以先看一看以下三题:

BZOJ3097:http://www.lydsy.com/JudgeOnline/problem.php?id=3097

BZOJ3098:http://www.lydsy.com/JudgeOnline/problem.php?id=3098

BZOJ3099:http://www.lydsy.com/JudgeOnline/problem.php?id=3099

如果你仔细研究过了(或者至少仔细看过AC人数的话),我想你一定会明白字符串哈希的正确姿势的_

完整解答

Python解法(不是)

print(len({input() for i in range(int(input()))}))

C++

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef unsigned long long ull;
int N, prime = 233317, ans = 1;
ull a[10010], mod = 212370440130137957, base=131;
char s[10010];
ull hashe(char s[]) {
	int len = strlen(s);
	ull ans = 0;
	for (int i = 0; i < len; i++) ans = (ans * base + ull(s[i])) % mod + prime;
	return ans;
}
int main() {
	scanf("%d", &N);
	for (int i = 0; i < N; i++) {
		scanf("%s", s);
		a[i] = hashe(s);
	}
	std::sort(a, a + N);
	for (int i = 0;i < N-1;i++)
	{
		if (a[i] != a[i + 1])
			ans++;
	}
	printf("%d", ans);
}