首页 > 其他分享 >浅谈字符串哈希

浅谈字符串哈希

时间:2023-06-25 22:33:42浏览次数:76  
标签:浅谈 int res len base 哈希 字符串 define

哈希HASH

哈希是对于字符串的一种操作。

在日常的百度搜索什么的都是根据关键字来查找,我们可以利用 hash 来加速这个过程。

哈希的思想

哈希其实是所有字符串操作中,最简单的操作了。哈希的过程,其实可以看作对一个串的单向加密过程,并且需要保证所加的密不能高概率重复,通过这种方式来替代一些很费时间的操作。

比如,最常见的,当然就是通过哈希数组来判断几个串是否相同(洛谷P3370)。此处的操作呢,很简单,就是对于每个串,我们通过一个固定的转换方式,将相同的串使其的“加密后的值”一定相同,不同的串尽量不同。

此处有人指出:那难道不能先比对字符串长度,然后比对 ASCLL 码之和吗?事实上显然是不行的(比如 ab 和 ba ,并不是同一个串,但是如是做却会让其认为是)。这种情况就叫做hash冲突,并且在如此的单向加密哈希中,hash 冲突的情况在所难免。

而我们此处介绍的,即是最常见的一种哈希:进制哈希。进制哈希的核心便是:给出一个固定进制 base,将一个串的每一个元素看做一个进制位上的数字,所以这个串就可以看做一个 base 进制的数,那么这个数就是这个串的哈希值;则我们通过比对每个串的的哈希值,即可判断两个串是否相同。

来练练手:

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

直接用 unsigned long long 自然溢出取模。

code:

#include <bits/stdc++.h>

#define int unsigned long long
#define N 10010

using namespace std;

const int base = 131;
int a[N], n, ans = 1;
char s[N];

inline int Hash(char s[])
{
    int len = strlen(s), res = 0;
    for(int i = 0; i < len; i ++)
        res = (res * base + (int)s[i]);
    return res;
}

signed main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        scanf("%s", s);
        a[i] = Hash(s);
    }
    sort(a + 1, a + n + 1);
    for(int i = 1; i < n; i ++)
        if(a[i] != a[i + 1]) ans ++;
    cout << ans << endl;
    return 0;
}

取模哈希

其实和上面的区别就是加了取模,当然也是对质数取模。

上面是用了 ull 自然溢出,但是自己取模更放心!

code:

#include <bits/stdc++.h>

#define int long long
#define P 998244353
#define N 10010

using namespace std;

const int base = 131;
int a[N], n, ans = 1;
char s[N];

inline int Hash(char s[])
{
    int len = strlen(s), res = 0;
    for(int i = 0; i < len; i ++)
        res = (res * base + (int)s[i]) % P;
    return res;
}

signed main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        scanf("%s", s);
        a[i] = Hash(s);
    }
    sort(a + 1, a + n + 1);
    for(int i = 1; i < n; i ++)
        if(a[i] != a[i + 1]) ans ++;
    cout << ans << endl;
    return 0;
}

双哈希

和上面的单哈希的区别就是多一个用不同质数取模的哈希值,更加安全,hash 冲突的几率变得更小。

#include <bits/stdc++.h>

#define int long long
#define P1 192608173
#define P2 998244353
#define N 100010

using namespace std;

const int base = 31;
int n, ans = 1;
char s[N];
struct sb{int h1, h2;}e[N];

inline int cmp(sb a, sb b)
{
    if(a.h1 == b.h1) return a.h2 < b.h2;
    else return a.h1 < b.h1;
}

inline int Hash1(char s[])
{
    int len = strlen(s), res = 0;
    for(int i = 0; i < len; i ++)
        res = (res * base + (int)s[i]) % P1;
    return res;
}

inline int Hash2(char s[])
{
    int len = strlen(s), res = 0;
    for(int i = 0; i < len; i ++)
        res = (res * base + (int)s[i]) % P2;
    return res;
}

signed main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        scanf("%s", s);
        e[i].h1 = Hash1(s);
        e[i].h2 = Hash2(s);
    }
    sort(e + 1, e + n + 1, cmp);
    for(int i = 1; i < n; i ++)
        if(e[i].h1 != e[i + 1].h1 && e[i].h2 != e[i + 1].h2) ans ++;
    cout << ans << endl;
    return 0;
}

关于效率:

自然溢出哈希快于取模单哈希快于双哈希。

主要还是在取模上面慢了。

但是双哈希的安全性更高,平常更推荐使用双哈希。

标签:浅谈,int,res,len,base,哈希,字符串,define
From: https://www.cnblogs.com/Multitree/p/17504162.html

相关文章

  • 字符串转hex
    12publicstaticStringtoHex(Stringtext)throwsException{34//将字符串转为GB2312数组5byte[]arr=text.getBytes("GB2312");67//将数组转为16进制字符串8StringhexStr="";9for(int......
  • Linux扩展篇-shell编程(八)-shell字符串截取
    shell字符串截取,一般包含从指定位置和从指定字符截取。一、从指定位置截取从字符串左边开始计数格式:${string:start:length}从string字符串的左边第start个字符开始,向右截取length个字符。${string:start}从string字符串的左边第start个字符开始截取,直到最......
  • 浅谈带宽的含义
    网络带宽是指在一个固定的时间内(1秒),能通过的最大位数据,或者可以认为在规定时间内从一端流到另一端的信息量,即数据传输率。就好像高速公路的车道一样,带宽越大,好比车道越多。网络带宽是互联网用户和单位选择互联网接入服务商的主要因素之一。网络流量就是网络上传输的数据量。虚拟主......
  • 【pycharm】替换字符串的三种方法
    一、场景  工作中我们可能需要修改一些字符串为同一字符串,此时pycharm的一些替换功能就很好用 二、快捷键1、基于当前文件CTRL+R2、基于全局的替换 CTRL+SHIFT+R  三、替换的三种方法1、基于Cc的字符串 这种最简单,就是简单的替换某个字符串为另一个,可以......
  • 格式化字符串输出
    在对字符串格式化进行输出时,最常见的方法就是使用%格式化字符串。这种方法虽然用法简单,但是在遇到需要有多个参数传入时就显得有些麻烦。其实还有以下几种格式化输出字符串的方法。str.format()str.format()对比之前最常用的方法,相当于用{}和:代替了%。str.format()在使用的时......
  • Shell判断是否包含给定字符串
    Shell判断是否包含给定字符串点击关注......
  • 记一次字符串末尾空白丢失的排查 → MySQL 是会玩的!
    开心一刻今天答应准时回家和老婆一起吃晚饭,但临时有事加了会班,回家晚了点回到家,本以为老婆会很生气,但老婆却立即从厨房端出了热着的饭菜老婆:还没吃饭吧,去洗下,来吃饭吧我洗好,坐下吃饭,内心感动十分;老婆坐旁边深情的看着我老婆:你知道谁最爱你吗我毫不......
  • [QML]从零开始QML开发(二)QML开发,浅谈控件、槽函数、锚等基本概念。QML和C++怎么交互?贯
    [QML]从零开始QML开发(二)QML开发,浅谈控件、槽函数、锚等基本概念。QML和C++怎么交互?贯彻落实MVC原则先看代码:importQtQuick2.12importQtQuick.Window2.12importQtQuick.Controls2.5Window{visible:truewidth:320height:480title:qsTr("HelloW......
  • 浅谈OpenCV的多对象匹配图像的实现,以及如何匹配透明控件,不规则图像
    浅谈OpenCV的多对象匹配透明图像的实现,以及如何匹配半透明控件引子OpenCV提供的templateMatch只负责将(相关性等)计算出来,并不会直接提供目标的对应坐标,一般来说我们直接遍历最高的相关度,就可以得到匹配度最高的坐标。但是这样一般只能得到一个坐标。在实际操作中,我们可能需要......
  • c语言-字符串+转义字符+注释、语句、函数、数组、操作符 2
    一、字符串+转义字符+注释字符串类型(相较于字符数据类型):eg:“”;//空字符串定义:由双引号引起的一串字符为字符串字面值,简称字符串。(后面默认会有\0,结束标志不算内容intmain(){chararr1[]="abc";//数组//"abc"——'a''b''c''\0'——'\0'......