字符串哈希

对于字符串的处理,有很多需要把重复字符串去掉的问题,但是直接比较字符串会出现很多问题。

例如,我将 "abc","bbb","cba",直接sb的变成数字进行比较,会导致将这三个字符串判断为一样的(233)

一般智商正常情况下 , 直接比较 判重 需要将字符串一个一个比对, 所以就会浪费大量时间。

这个时候我们就需要将字符串转化为一定大小的数字来进行储存。这就需要我们来使用hash。

那么哈希的原理是什么呢?哈希的原理就是将·字符串中每一个字符乘上一个数字(像进制转换那样搞成一个数)(一般是一个质数,具体原因我也不清楚,希望有dalao能在评论里指出来。)

就是把字符串搞成一个很好的数字放到bool数组里进行判重,

#include<bits/stdc++.h>
using namespace std;
#define X 127
const int N=10005;
typedef unsigned long long Ull;
int n,ans;
Ull a[N];
char s[N];
int HASH(){
	scanf("%s",s+1);
	int len=strlen(s+1);
	int Hash=0;
	for(int i=1;i<=len;i++){
	Hash=Hash*X+s[i]-‘a‘;
	}
	return Hash;
}

  至于为什么用unsigned long long 来储存是为了防止字符串太大溢出,使用unsigned long long可以在溢出的情况下大概率保证hash值不同(还是有非酋会撞上相同的情况)。

  然后就可以利用hash值来对比两个字符串是否相等。

  附上几道hash水题

  洛谷3370 模板题

#include<bits/stdc++.h>
using namespace std;
#define X 127
const int N=10005;
typedef unsigned long long Ull;
int n,ans;
Ull a[N];
char s[N];
int HASH(){
	scanf("%s",s+1);
	int len=strlen(s+1);
	int Hash=0;
	for(int i=1;i<=len;i++){
	Hash=Hash*X+s[i]-‘a‘;
	}
	return Hash;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		a[i]=HASH();
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		if(a[i]!=a[i+1])ans++;
	}
	printf("%d",ans);
	return 0;
}

  codevs 2875

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define X 127
#define mod 999991
bool a[mod+6];
int n,m;
int Hash(){
	char s[1100];
	scanf("%s",s+1);
	int tot=0;
	int len=strlen(s+1);
	for(int i=1;i<=len;i++){
		tot=(tot*X+s[i]-‘a‘)%mod;
	}
	return (tot%mod);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		a[Hash()]=1;
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		if(a[Hash()])printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

   还有一道bzoj水题 可以练习hash和平衡树

   bzoj 2761

   hash做法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define mod 1999
#define N 50010
bool Hash[N];
int cnt,a[N],to[N],n;
int head[N];
inline bool judge(int x){
	if(!Hash[x])return 0;
	for(int i=head[x];i;i=to[i]){
		if(a[i]==x)return 1;
	}
	return 0;
}
inline void insert(int x){
	Hash[x]=1;
	a[++cnt]=x;
	to[cnt]=head[x];
	head[x]=cnt;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		cnt=0;
		memset(head,0,sizeof(head));
		memset(to,0,sizeof(to));
		memset(a,0,sizeof(a));
		scanf("%d",&n);
		int x=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&x);
			if(judge(x))continue;
			insert(x);
			if(i==1)printf("%d",x);
			else printf(" %d",x);
		}
		printf("\n");
	}
	return 0;
}
/*
2

11

1 2 18 3 3 19 2 3 6 5 4

6

1 2 3 4 5 6
 */

  

 当我们计算两个不同的字符串 有可能凑巧他们的hash值是相等的 ,于是就可以每个字符串算出两个hash值

 附上恶心的双hash代码(看一看找个乐子就行了 ,这种恶心的代码除了J1m没人会写的,还是去学STLmap吧)



//输入+双哈希
    for(int k=1;k<=N;k++,M++)
    {
        char s1[12],s2[12];
        scanf("%s %s",s1,s2);
       long long h3=0,h4=0;
       for(int i=0;i<strlen(s1);i++)h3=(h3*Jin+s1[i])%mod,h4=(h4*Kai+s1[i])%mod;
        if(size[h3])
            for(int i=1;i<=size[h3]+1;i++)
            {
                if(hash[h3][i][0]==h4){x[M]=hash[h3][i][1];break;}
                if(i==size[h3]+1){size[h3]++,hash[h3][i][0]=h4,hash[h3][i][1]=++cnt,x[M]=cnt;break;}
            }
        else size[h3]++,hash[h3][1][0]=h4,hash[h3][1][1]=++cnt,x[M]=cnt;

  

时间: 2024-08-09 06:24:18

字符串哈希的相关文章

洛谷——P3370 【模板】字符串哈希

题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:) 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明

字符串哈希(自然溢出模板)

P3370 [模板]字符串哈希 题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明 时空限制:1000ms,128M 数据

UvaLive 6439 Pasti Pas! 字符串哈希

链接:http://vjudge.net/problem/viewProblem.action?id=47586 题意:给一个字符串,可以将从前数第i~j和从后数第i~j字符串看作一个字符,问整段字符串看作一个回文里有多少个字符. 思路:字符串哈希,从前开始哈希也从后开始哈希,遇到哈希值相同就多两个字符,最后处理一下中间的字符即可. 代码: #include <iostream> #include <cstdio> #include <cstring> #include

HDU 4821 杭州现场赛:每个片段字符串哈希比较

I - String Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4821 Description Given a string S and two integers L and M, we consider a substring of S as "recoverable" if and only if (i) I

HDU--4821(字符串哈希)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821 用到了BKD字符串哈希的方法,一直不是很会哈希,总是用map,但是很显然,map并不是万能的. 用哈希的方法可以递推的求出所有子串的哈希值,最后用map维护答案即可:注意下long long #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include&

[模板]字符串哈希的简易做法

题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:) 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明

【NOIP模拟】Grid(字符串哈希)

题目背景 SOURCE:NOIP2016-RZZ-1 T3 题目描述 有一个 2×N 的矩阵,矩阵的每个位置上都是一个英文小写字符. 现在需要从某一个位置开始,每次可以移动到一个没有到过的相邻位置,即从 (i,j) 可以移动到 (i-1,j)(i+1,j)(i,j-1)(i,j+1) (要求该位置在矩阵上且之前没有到过). 从选取的起点开始,经过 2N-1 次移动后,将会走过矩阵的每一个位置,将移动经过的格子依次取出来就得到了一个长度为 2N 的串. 可以任意选择起点和终点,任意选择移动方案,求

洛谷 P3370 【模板】字符串哈希

题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:) 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明

HDU 3973 AC&#39;s String 字符串哈希

HDU 3973 通过哈希函数将一个字符串转化为一个整数,通过特定的方式可以使得这个哈希值几乎没有冲突(这就是关键之处,几乎没有视为没有= =!, 其实也可以考虑实现哈希冲突时的处理,只是这道题没必要而已),然后使用线段树维护修改后的哈希值. 因为输入的字符串只有26个,考虑使用一个大于等于26的素数p作为进制,然后将原串转化为一个p进制的数mod 2^63(也相当于自然溢出),然后这个数存入map中,然后使用线段树维护长串区间的哈希值,hash[l, r]表示将区间[l, r]的字符串转化为p

luogu P3370 【模板】字符串哈希

题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:) 输入输出格式 输入格式: 第一行包含一个整数N,为字符串的个数. 接下来N行每行包含一个字符串,为所提供的字符串. 输出格式: 输出包含一行,包含一个整数,为不同的字符串个数. 输入输出样例 输入样例#1: 5 abc aaaa abc abcc 12345 输出样例#1: 4 说明