哈希冲突 及 双哈希

前言

若不知道 哈希和字符串哈希 看我上一个作品:

字符串哈希从入门到精通

今天讲的约等于它的拓展......

一.解决哈希冲突

1.1 基本概念

字符串哈希不同字符串映射成不同的整数。

思想 :将字符串映射成一个 p进制数字

我们定义如下哈希函数 :(该字符串下标从1开始

​​​​​​​

例如:p = 131,s = abc,其哈希值为 ​​​​​​​

但是,有时会存在多个不同的字符串哈希值相同 的情况,我们通常的处理方式是调整p和M的值 ,取p为质数,M为大质数

M 我们要取一个比较大的质数,但是可恶的出题人往往对一些质数如1e9 + 7、998244353等搞一些卡哈希的数据 (恶心)(往往通过生成一个随机数 ,根据随机数再取质数 ,去避免卡hash

当然我们肯定是有解决方案了,那就是我们今天要讲的双哈希!!!(其实还有许多方法但考试一般只需要双哈希就够了,如果在意可以去了解一下)

双哈希有多强呢?有一道题叫 "++Hash Killer III++" 题目大概就是让你造数据去卡他的双哈希,直到出题网站倒闭这个题也没人A......

接下来给大家带来方法......

1.2 实现方式

双哈希顾名思义就是模两次hash 防止出题人的狡猾

整理了一个模板++(仅供参考)++

cpp 复制代码
struct HASH{
	long long sed,mod,h[N],pw[N];
	void init(int ser_in,int mod_in){
		sed=ser_in,mod=mod_in;
		pw[0]=1;
		for(int i=1;i<N;i++){
			pw[i]=pw[i-1]*sed%mod;
		}
	} 
	void make(string s){
		h[0]=s[0]%mod;
		for(int i=1;i<s.size();i++){
			h[i]=(h[i-1]*sed%mod+s[i])%mod;
		}
	}//构造hash
	long long get(int l,int r){
		return (h[r]-h[l-1]*pw[r-l+1]%mod+mod)%mod;
	}//取子串可以根据题目使用
}S1,S2;

该怎么用呢?来个题试试!!!

二.例题《不同子串》

2.1 题目描述

2.2 思路

我们输入完后建立一个pair数组去记录我们的双哈希 ,然后将数组排序 方便下面比较,比较这一个的哈希值与前一个的哈希值**(我们已经排序了所以前面的要么比他小,要么相等)** 是否相等,如果不相等或i==1 ,那么不同的字串+1

2.3 代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
string s;
int n,l;
const int N=1e6+5;
struct HASH{
	long long sed,mod,h[N],pw[N];
	void init(int ser_in,int mod_in){
		sed=ser_in,mod=mod_in;
		pw[0]=1;
		for(int i=1;i<N;i++){
			pw[i]=pw[i-1]*sed%mod;
		}
	} 
	void make(string s){
		h[0]=s[0]%mod;
		for(int i=1;i<s.size();i++){
			h[i]=(h[i-1]*sed%mod+s[i])%mod;
		}
	}
	long long get(int l,int r){
		return (h[r]-h[l-1]*pw[r-l+1]%mod+mod)%mod;
	}
}S1,S2;//模板
int idx;
pair<long long,long long> ans[N];//双哈希数组
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int cnt=0;
    cin>>n>>l;
    cin>>s;
    s=" "+s;
    S1.init(114,1e9+7);
    S2.init(114514,998244353);//构造
    S1.make(s);
    S2.make(s);//构建整个字符串的哈希
    for(int i=1;i<=n-l+1;i++){
        ans[++idx].first=S1.get(i,i+l-1);
        ans[idx].second=S2.get(i,i+l-1);//截取字串
    }
    sort(ans+1,ans+idx+1);
    for(int i=1;i<=idx;i++){
        if(ans[i]!=ans[i-1]||i==1){//判断是否为不同字串
            cnt++;
        }
    }
    cout<<cnt;//输出
    return 0;
}

加纳!!!!!

相关推荐
REDcker35 分钟前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
Yzzz-F1 小时前
Problem - 2205D - Codeforces
算法
我命由我123452 小时前
Kotlin 开发 - lateinit 关键字
android·java·开发语言·kotlin·android studio·android-studio·android runtime
智者知已应修善业2 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
Halo_tjn2 小时前
Java Set集合相关知识点
java·开发语言·算法
许彰午3 小时前
我手写了一个 Java 内存数据库(二):B+ 树的插入与分裂
java·开发语言·面试
大飞记Python3 小时前
【2026更新】Python基础学习指南(AI版)——04数据类型
开发语言·人工智能·python
生成论实验室3 小时前
《事件关系阴阳博弈动力学:识势应势之道》第四篇:降U动力学——认知确定度的自驱演化
人工智能·科技·神经网络·算法·架构
AI科技星3 小时前
全域数学·72分册:场计算机卷【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算
Alice-YUE3 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript