当前位置: 首页 > news >正文

NO.80十六届蓝桥杯备战|数据结构-字符串哈希|兔子与兔子(C++)

  1. 回忆:哈希函数与哈希冲突
  • 哈希函数:将关键字映射成对应的地址的函数,记为 Hash(key) = Addr
  • 哈希冲突:哈希函数可能会把两个或两个以上的不同关键字映射到同⼀地址,这种情况称为哈希冲突。
  1. 字符串哈希
    定义⼀个把字符串映射到整数的函数hash ,这就是字符串哈希。说⽩了,就是将⼀个字符串⽤⼀个整数表⽰。
  2. 字符串哈希中的哈希函数
    在字符串哈希中,有⼀种冲突概率较⼩的哈希函数,将字符串映射成p 进制数字
    h a s h ( s ) = ∑ i = 0 n − 1 s [ i ] × p n − i − 1 ( M O D M ) hash(s) = \sum^{n-1}_{i=0} s[i] \times p^{n-i-1} (MOD M) hash(s)=i=0n1s[i]×pni1(MODM)
    其中,p通常取质数131或者13331。如果把哈希值定义为unsigned long long类型,在C++中,溢出就会⾃动取模。
    但是,实际求哈希值时,我们⽤的是前缀哈希的思想来求,这样会和下⾯的多次询问⼦串哈希⼀致
  3. 前缀哈希数组
    单次计算⼀个字符串的哈希值复杂度是O(N)。如果需要多次询问⼀个字符串的⼦串的哈希值,每次重新计算效率⾮常低下。
    ⼀般利⽤前缀和思想先预处理字符串中每个前缀的哈希值,这样的话每次就能快速求出⼦串的哈希了
    在这里插入图片描述
typedef unsigned long long ULL;  
const int N = 1e6 + 10, P = 13331;  
char s[N];  
int len;  
ULL f[N]; // 前缀哈希数组  
ULL p[N]; // 记录 p 的 i 次⽅  
// 处理前缀哈希数组以及 p 的 i 次⽅数组  
void init_hash()  
{  
	f[0] = 0; p[0] = 1;  
	for(int i = 1; i <= len; i++)  
	{  
		f[i] = f[i - 1] * P + s[i];  
		p[i] = p[i - 1] * P;  
	}  
}  
// 快速求得任意区间的哈希值  
ULL get_hash(int l, int r)  
{
	return f[r] - f[l - 1] * p[r - l + 1];  
}

如果题⽬只是简单的求单个字符串的哈希值:

typedef unsigned long long ULL;  
const int N = 1e6 + 10;  
int len;  
char s[N];  
ULL gethash()  
{  
	ULL ret = 0;  
	for(int i = 1; i <= len; i++)  
	{  
		ret = ret * p + s[i];  
	}  
	return ret;  
}
P3370 【模板】字符串哈希 - 洛谷
#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ULL;

const int N = 1e4 + 10, P = 131;

int n;
int a[N];

ULL get_hash(string& s)
{
    ULL ret = 0;
    for (int i = 1; i <= s.size(); i++)
    {
        ret = ret * P + s[i-1];        
    }
    return ret;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        string s; cin >> s;
        a[i] = get_hash(s);
    }

    int ret = 1;
    sort(a+1, a+1+n);
    for (int i = 2; i <= n; i++)
    {
        if (a[i] != a[i-1]) ret++;        
    }

    cout << ret << endl;
    
    return 0;
}
P10468 兔子与兔子 - 洛谷
#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ULL;

const int N = 1e6 + 10, P = 13331;

int n;
string s;
ULL f[N]; //前缀哈希数组
ULL p[N]; //p的i次方

void init_hash()
{
    p[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        f[i] = f[i-1] * P + s[i];
        p[i] = p[i-1] * P;
    }
}

ULL get_hash(int l, int r)
{
    return f[r] - f[l-1] * p[r-l+1];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> s;
    n = s.size();
    s = " " + s;

    init_hash();
    
    int m; cin >> m;
    while (m--)
    {
        int l1, r1, l2, r2; cin >> l1 >> r1 >> l2 >> r2;

        ULL x = get_hash(l1, r1), y = get_hash(l2, r2);

        if (x == y) cout << "Yes" << endl;
        else cout << "No" << endl;
    }
    
    return 0;
}
http://www.dtcms.com/a/122777.html

相关文章:

  • CCRC 与 EMVCo 双认证:中国智能卡企业的全球化突围
  • git 总结遇到的问题
  • B+树与红黑树
  • 第三章:SQL 高级功能与性能优化
  • CentOS 中下载rpm包并安装
  • PhpStorm配置函数和文件注释模板
  • Python设计模式:工厂模式
  • 凯斯西储大学CWRU数据集变体
  • python中的数据模型-pydantic浅讲
  • 02_SQL分库分表及Java实现
  • 【重构谷粒商城12】npm快速入门
  • Python第八章:数据可视化——Json数据
  • Android 开发中compileSdkVersion 和 targetSdkVersion
  • Vue2下载二进制文件
  • 【动手学深度学习】LeNet:卷积神经网络的开山之作
  • 【面试】封装、继承、多态的具象示例 模板编程的理解与应用场景 链表适用的场景
  • 【vue】slot插槽:灵活内容分发的艺术
  • R语言——散点图
  • 第九章:可靠通信_《凤凰架构:构建可靠的大型分布式系统》
  • WHAT - React useId vs uuid
  • Pascal VOC 2012 数据集格式与文件结构
  • 前端性能优化的全方位方案【待进一步结合项目】
  • Redis 持久化+性能管理+缓存
  • XSS靶场闯关小游戏
  • 10A 大电流 DCDC 降流芯片 WD5030
  • 2025年AI开发学习路线
  • springboot集成大华人脸机
  • js实现跨域下载,展示下载进度以及自定义下载名称功能
  • Docker新型容器镜像构建技术,如何正确高效的编写Dockerfile
  • 前端三件套—CSS入门