HASH 字符串哈希 映射转化

哈希HASH的本质思想类似于映射、离散化。

哈希,通过给不同字符赋不同的值、并且钦定一个进制K和模数,从而实现一个字符串到一个模意义下的K进制数上。

它的主要目的是判重,用于DFS、BFS判重(八数码),字符串判断相等、出现等等。

本篇总结字符串哈希以及一些应用例题。

为什要用字符串哈希?

因为取出一个字符串是O(n)的,比较一遍又是O(n)的,况且要比较两个甚至多个。这就成了n^2级别的了。

那我们比较数字怎么就不用这么麻烦呢?因为数字可以直接比较,(虽然不知道内部是怎么实现的,反正比一位一位比较肯定快)所以我们考虑把字符串映射到数字上。

就有了字符串哈希。

通过字符串哈希,只要题目支持预处理,我们可以O(n)预处理之后,O(1)进行提取,O (1)进行判重。

字符串哈希需要什么?

1.字符。初始坐标无所谓。

2.K进制数,通常选择131,13331,这两个质数冲突几率很小(不要问我为什么)。

3.取模数,我用过 1e9+7,998244353,用2^64也可以,这里利用自然溢出,一般不会有问题。提一句,unsigned long long做减法,即使算出来应该是负数,会自动加上2^64,相当于(a+mod-b)%mod了。没有问题。

处理hash:

1.预处理K^len 放入k[]中储存。

2.顺便处理hash[i]=hash[i-1]*K+str[i]

字符串哈希的基本操作:

1.提取:a[l,r]段:hash[r]-hash[l-1]*k[r-l] 类似前缀和。

2.插入,同处理。

操作均是O(1)

字符串哈希支持的应用操作:

1.判断字符串是否相等。取hash段比较即可,O(1)

2.找某两个位置开始的LCP(最长公共前缀),二分位置+hash判断 O(logn) (长度够小,可用trie树,更好的支持多串LCP)

3.判断两个串字典序大小,找LCP,判断下一位大小。O(logn)

字符串哈希例题:

T1:POJ2758

给定一个字符串,要求维护两种操作
在字符串中插入一个字符
询问某两个位置开始的LCP
插入操作<=200,字符串长度<=5w,查询操作<=2w

分析:有人用后缀数组??不会。Splay??不会。

操作小于等于200,直接暴力重构是正解!!

注意:

1.插入字符位置可能远大于len,要向len+1取min

2.询问位置是初始位置,重构的时候,可以暴力循环记录每一个初始位置现在已经变到了第几个位置。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=80000+210;
const int mod=998244353;
const int K=13331;
ll h[N];
ll c[N];
int n,m;
int len;
int f[N];
int ne[N];
char o[N],a[N];
int main()
{
    scanf("%s",o+1);
    n=strlen(o+1);
    memcpy(a+1,o+1,sizeof o);len=n;
    //cout<<" lenn "<<len<<endl;
    scanf("%d",&m);
    for(int i=1;i<=n;i++) ne[i]=i;
    c[0]=1;
    for(int i=1;i<=n+m+1;i++) {
    c[i]=(c[i-1]*K)%mod;
    if(i<=n) h[i]=(h[i-1]*c[1]+(int)o[i])%mod;
    }
    char ch,op;
    int num,x,y;
    //cout<<"fir "<<a+1<<endl;
    while(m--){
        scanf(" %c",&op);

        if(op==‘Q‘){
            scanf("%d%d",&x,&y);
            x=ne[x],y=ne[y];
            //cout<<x<<" and "<<y<<endl;
            if(a[x]!=a[y]){
                printf("0\n");continue;
            }
            int ans;
            int l=0,r=min(len-x,len-y)+1;
            //cout<<" origin "<<l<<" "<<r<<endl;
            while(l<=r){
                int mid=(l+r)>>1;
                int ed1=x+mid-1;
                int ed2=y+mid-1;
                ll ha1=(h[ed1]+mod-h[x-1]*c[mid]%mod)%mod;
                ll ha2=(h[ed2]+mod-h[y-1]*c[mid]%mod)%mod;
                //cout<<mid<<" hash "<<ha1<<" "<<ha2<<endl;
                if(ha1==ha2) {
                    ans=mid,l=mid+1;
                }
                else{
                    r=mid-1;
                }
            }
            printf("%d\n",ans);
        }
        else{
            scanf(" %c%d",&ch,&num);
            if(num>len) num=len+1;
            ///add(num);
            len++;
            for(int i=len;i>=num+1;i--) a[i]=a[i-1];
            a[num]=ch;
            for(int i=num;i<=len;i++) h[i]=(h[i-1]*c[1]+(int)a[i])%mod;
            for(int i=n;i>=1;i--) {
            if(ne[i]>=num) ne[i]++;else break;}
        }
        //cout<<a+1<<endl;
    }
    return 0;
}

POJ2758

原文地址:https://www.cnblogs.com/Miracevin/p/9153309.html

时间: 2024-10-07 10:24:20

HASH 字符串哈希 映射转化的相关文章

luoguP3370 【模板】字符串哈希 [hash]

题目描述 如题,给定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

哈希映射

哈希来源问题:关于统计一个字符串集合中,求出现次数最多的字符串思路:建立一个哈希映射(HashMap),其键为"字符串",值为"字符串出现次数",然后遍历字符串集合,如果字符串已存在,将键为该字符串的值加1,否则添加键值对".. 详解javascript哈希映射的HashMap 参考脚本之家 http://www.jb51.net/article/84771.htm Hash Map 的简单实现 //定义一个Hash Map var hashMap={ S

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

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

oracle 表连接 - hash join 哈希连接

一. hash 连接(哈希连接)原理 指的是两个表连接时, 先利用两表中记录较少的表在内存中建立 hash 表, 然后扫描记录较多的表并探測 hash 表, 找出与 hash 表相匹配的行来得到结果集的表连接方法. 哈希连接仅仅能用于等值连接条件(=). 如果以下的 sql 语句中表 T1 和 T2 的连接方式是哈希连接, T1 是驱动表 select * from T1, T2 where T1.id = T2.id and T1.name = 'David'; oracle 运行过程例如以下

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

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

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

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

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

luogu P3370 【模板】字符串哈希

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