首页 > 其他分享 >字符串哈希 详解+例题

字符串哈希 详解+例题

时间:2024-08-27 19:47:42浏览次数:5  
标签:cnt 前缀 int long 详解 哈希 字符串 例题

字符串哈希

观看讲解视频:董晓算法 做的笔记

理论部分

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

  • 对于一个长度为 \(n\) 的字符串 \(s\),我们定义它的 Hash 函数为:
    \(h(s) = \Sigma ^n_{i=1}\) \(s[i] \times p^{n-i}\) \((mod\) \(m)\)
    例如:字符串 \(abc\),他的 hash 函数值为 \(ap^2+bp^1+cp^0\)
    即 \(97\times131^2+98\times131^1+99\)

  • 如果两个字符串不一样,Hash 值却一样,这样的现象称为 哈希碰撞

  • 解决哈希碰撞的方法:
    保证 \(p\)、\(m\) 互质,\(p\) 通常取质数 \(131\) 或 \(13331\);\(m\) 通常取大整数 \(2^64\),哈希函数要定义为 ULL(unsigned long long),超过则自动溢出,等价于取模。

关于 unsigned long long:无符号,取值范围在 \(0 \sim 2^{64}\)

代码实现:

  1. 求一个字符串的哈希值:前缀和
    前缀和:\(h[i] = h[i-1] \times p + s[i]\),\(h[0] = 0\) (\(h[i]\) 表示前 \(i\) 项的 hash 值)
    时间复杂度:\(O(n)\)
  2. 他的子串的哈希值就是区间和
    区间和:\(h[l,r] = h[r] - h[l] \times p^{r-l+1}\)
    时间复杂度:\(O(1)\)

例题:

P3370 【模板】字符串哈希

模板题,直接上代码。

#include<bits/stdc++.h>

using namespace std;

#define ULL unsigned long long

const int maxn=100010;
const int p=131;

int n;
int lens;
char s[maxn];
ULL ans[maxn],h[maxn];
int cnt=0;

ULL calc(char s[],int n)
{
	h[0]=0;
	for(int i=1;i<=lens;i++)
	{
		h[i]=h[i-1]*p+s[i]; //求 hash 值,前缀和,便于求区间 hash 值(虽然这题不需要 QWQ ) 
	}
	return h[lens];
 } 
 //计算哈希值 

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		lens=strlen(s+1);
		ans[i]=calc(s,lens);//计算哈希值
	}
	sort(ans+1,ans+1+n);
	for(int i=1;i<=n;i++)
	{
		if(ans[i]!=ans[i-1])cnt++;
	 } 
	cout<<cnt<<endl;
	return 0;
} 

魔族密码

题目意思:

求最长词链。(其实就是关于字符串的最长上升子序列了)
输入保证了字符串按字典序排列且没有重复的(太良心了)

词链:多个词组成的表中,前一个单词是后一个单词的前缀。

思路:

不是吧??我这个蒟蒻都想起来了两种方法。。(虽然只会实现一种)

  • 一看前缀,就是字典树
    让节点的 cnt 值表示有多少个 s 在这里结尾
    每次插入一个字符串,查找这个字符串经过节点的 cnt 值之和
    跟原答案求一个 max 值
    代码:
#include<bits/stdc++.h>

using namespace std;

int n;
int ans=0;
int cnt=1;

struct node{
	int son[65];
	int cnt;
}z[3000100];

int getnumber(char ch)
{
	return ch-'a'+1;
}

void insert(string s)
{
	int now=1;
	int cnt_s=1;
	for(int i=0;i<s.length();i++)
	{
		int num=getnumber(s[i]);
		if(!z[now].son[num])
			cnt++,z[now].son[num]=cnt;
		cnt_s+=z[now].cnt;
		now=z[now].son[num];
	}
	z[now].cnt++;
	ans=max(ans,cnt_s);
	return;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		string s;
		cin>>s;
		insert(s);
	}
	cout<<ans<<endl;
	return 0;
}
  • 但是标签里哈希
    考虑哈希做法,此处参考 https://www.luogu.com.cn/article/bu7eorhv
    因为输入保证按照字典序排列,因此如果 \(s_j\) 是 \(s_i\) 的前缀,则必然会有 \(j < i\)。
    这样在计算 \(h(s_i)\) 的值的时候,计算每个前缀和的时候,查找一下前面是否有这一个值就行了。
    我们可以推出状态转移方程:\(dp_i = max\) \(\{{dp_i},{dp_j+ 1}\}\)
    代码:我说没有行吗。。。(逃
    其实是我不会

完结撒花!

标签:cnt,前缀,int,long,详解,哈希,字符串,例题
From: https://www.cnblogs.com/lazy-ZJY0307/p/18381339

相关文章

  • C语言字符函数和字符串函数的详解及模拟实现(超详细)
    目录1.求字符串长度1.1strlen1.1.1.strlen函数介绍1.1.2.strlen函数模拟实现 2.长度不受限制的字符串函数 2.1strcpy2.1.1.strcpy函数介绍2.1.2.strcpy函数模拟实现 2.2strcat2.2.1.strcat函数介绍2.2.2.strcat函数模拟实现 2.3strcmp 2.3.1.strcmp函数介绍......
  • 详解 dotenv 的使用与实现
    每当涉及到保护API密钥或我们不想因为开源项目而向公众展示的东西时,我们总是倾向于.env文件,而它的解析依赖到dotenv包,一个每周都有31k+开发人员下载的软件包。其设计的理念是Twelve-FactorApp的第三点。配置与代码分离。关于Twelve-FactorApp大家可以前往这里查看:https://12fa......
  • ES6的Map函数详解
    一、Map介绍Map对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者基本类型)都可以作为一个键或一个值Map对象是键值对的集合。Map中的一个键只能出现一次;它在Map的集合中是独一无二的。Map对象在for…of循环在每次迭代后会返回一个形式为[key,value]的数组......
  • 遥控链路应用行业行业详解!!!
    遥控链路,即遥控器和接收机之间的信号传输链路,其应用行业广泛且多样。1.家电行业传统家电控制:如电视、空调、音响等设备,通过遥控器实现远程控制,极大地方便了用户的日常生活。这些遥控器通过红外线信号或无线电波将控制指令传输给设备,设备内部的接收器接收并解码信号,从而执行......
  • 访问者模式详解
    访问者模式简介:类的内部结构不变的情况下,不同的访问者访问这个对象都会呈现出不同的处理方式。人话:其实就是为了解决类结构不变但操作处理逻辑易变的问题,把对数据的操作都封装到访问者类中,我们只需要调用不同的访问者,而无需改变改变结构类,实现了。举个理发店的例子......
  • 分布式搜索引擎 数据聚合详解
    1.数据聚合**聚合(aggregations)**可以让我们极其方便的实现对数据的统计、分析、运算。例如:什么品牌的手机最受欢迎?这些手机的平均价格、最高价格、最低价格?这些手机每月的销售情况如何?实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现近实时搜索效......
  • Fluent热对流理论详解
    1.牛顿冷却公式流体流过固体表面发生的热量交换称为对流换热。对流换热的基本公式为牛顿冷却公式,即图对流换热示意图对流换计算的关键在于获得流体与固体表面间的传热系数。对流换热是流体得导热和对流两种基本传热方式共同作用的结果。斯坦顿数:Stantonnumber简介:......
  • Android taskset用法详解
    一、简介taskset命令用于设置或者获取一直指定的 PID 对于CPU核的运行依赖关系。通过taskset命令可将某个进程与某个CPU核心绑定,使得其仅在与之绑定的CPU核心上运行关于绑核的解释绑核,其实就是设定某个进程/线程与某个CPU核的亲和力(affinity)。设定以后,Linux调......
  • 算法与数据结构——哈希表
    哈希表哈希表(hashtable),又称散列表,它通过建立键key与值value之间的映射,实现高效的元素查询。具体而言,我们向哈希表中输入一个键key,则可以在O(1)时间内获取对应的值value。除哈希表外,数组和链表也可以实现查询功能,他们的效率对比如下表:添加元素:仅需将元素添加至数组(链表)的尾部......
  • C++与C语言中基础数据类型详解
    目录引言基础数据类型分类实际编程中的应用建议结论引言在C++与C语言的编程世界中,理解并正确使用基础数据类型是每个程序员的必备技能。不同的数据类型在内存中的占用和表示方式直接影响到程序的性能和行为。本文将详细介绍C++与C语言中常见的基础数据类型,探讨它们......