首页 > 其他分享 >万能的哈希

万能的哈希

时间:2024-07-17 20:40:10浏览次数:14  
标签:ch int 万能 哈希 mathcal dp 回文

本章节将介绍哈希如何实现 KMP 与 manacher。

KMP

我们对于文本串 \(s\) 和模式串 \(t\),先用一个数组 \(has_i\) 表示 \(s\) 中 前 \(i\) 位的哈希值,用 \(hat\) 表示 \(t\) 的哈希值。

然后遍历 \(s\),计算以第 \(i\) 位为起点的长度为 \(|t|\) 的区间的哈希值,与 \(hat\) 比较,累加答案即可。

跑得飞快。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e6+10;
char s[maxn],t[maxn];
int n,m,ans;
int hat,has[maxn],p[maxn]={1};
int work(int l,int r)
{
	return has[r]-has[l-1]*p[r-l+1];
}
signed main()
{
	cin>>(s+1)>>(t+1);
	n=strlen(s+1),m=strlen(t+1);
	for(int i=1;i<=n;i++)
	{
		has[i]=has[i-1]*131+(s[i]-'0');
		p[i]=p[i-1]*131;
	}
	for(int i=1;i<=m;i++)hat=hat*131+(t[i]-'0');
	for(int l=1;l<=n-m+1;l++)
	{
		int r=l+m-1;
		if(work(l,r)==hat)ans++;
	}
	cout<<ans;
	return 0;
}

manacher

这个稍微复杂一点,不过也不难。

设原字符串为 \(s\),先预处理从后往前和从前往后两个哈希数组,设为 \(fr\) 和 \(en\)。那么对于一个子串 \(s_{l,r}\),设 \(get1\),\(get2\) 分别为两个哈希数组对于该区间的哈希值,那么它是回文串的充要条件为 \(get1=get2\),从而可以做到 \(\mathcal{O}(1)\) 判断回文串。

朴素做法是 \(\mathcal{O}(n^3)\) 的,用上述做法可以优化到 \(\mathcal{O}(n^2)\),依然过不去,怎么办呢?

考虑设 \(dp_r\) 表示以 \(r\) 结尾的最长回文串长度。容易发现如果一个回文串以 \(r\) 结尾,如果把长度为 \(1\) 的串特判掉以后,它一定是由一个以 \(r-1\) 结尾的回文串拼接两个字符组成的。

所以就找到以 \(r-1\) 结尾的回文串之前的那个字符,容易推出它的位置是 \(r-dp_{r-1}\),然后我们定义 \(l\) 为从刚刚提到的位置向右移动时当前的位置,那么我们用哈希 \(\mathcal{O}(1)\) 判断当前串 \([l,r]\) 是否为回文串,然后如果是跳出循环,否则 \(l++\) 即可。

最后遍历 \(dp\) 数组,找到最大值输出即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1.1e7+10;
char s[maxn];
int n,fr[maxn],en[maxn],p[maxn];
int dp[maxn];
bool check(int l,int r)
{
	int get1=fr[r]-fr[l-1]*p[r-l+1];
	int get2=en[l]-en[r+1]*p[r-l+1];
	return get1==get2;
}
signed main()
{
	cin>>(s+1);
	n=strlen(s+1);p[0]=1;
	for(int i=1;i<=n;i++){fr[i]=fr[i-1]*171+(s[i]-'0');p[i]=p[i-1]*171;}
	for(int i=n;i>=1;i--){en[i]=en[i+1]*171+(s[i]-'0');}
	dp[1]=1;dp[2]=(s[1]==s[2]?2:1);
	for(int r=3;r<=n;r++)
	{
		int l=r-dp[r-1];
		if(l!=1)l--;
		while(l<r)
		{
			if(check(l,r))break;
			l++;
		}
		dp[r]=r-l+1;
	}
	int ans=0;
	for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
	cout<<ans;
	return 0;
}

标签:ch,int,万能,哈希,mathcal,dp,回文
From: https://www.cnblogs.com/Lydic/p/18308250

相关文章

  • 【数据结构与算法】选择排序篇----详解直接插入排序和哈希排序【图文讲解】
     欢迎来到CILMY23的博客......
  • 代码随想录之哈希表
    1、有效的字母异位词给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。注意:若s和t中每个字符出现的次数都相同,则称s和t互为字母异位词。示例1:输入:s="anagram",t="nagaram"输出:true示例2:输入:s="rat",t="car"输出:......
  • golang 实现负载均衡器-一致性哈希算法负载均衡器代码实现-2.0-xunznux
    go实现负载均衡器代码细节文章目录go实现负载均衡器代码细节代码实现原理介绍版本1.0版本2.05、负载均衡器接口增加方法AddServer以加权轮询负载均衡为例展示(SelectServer增加request和AddServer的实现):6、IP散列负载均衡7、一致性哈希负载均衡策略其他内容Lab1:M......
  • Day3 设计哈希集合
    classMyHashSet{  private:    vector<list<int>>data;    staticconstintbase=769;    staticinthash(intkey){      returnkey%base;    }public:  MyHashSet():data(base){}    voidadd(......
  • 哈希表原理
    哈希表(键值对)键(key):类似于数组的下标,可以为任意类型,但是不能重复值(val):类似于数组的元素,可以为任意类型哈希表不存在元素访问溢出的情况,只要访问未创建的元素,便会创建一个值为0的键值对哈希表的插入://方法一:【】法(中括号法)//方法二:insert()函数插入法#include<iostream......
  • 分库分表策略深入解析:基于范围(Range)、基于哈希(Hash)以及基于映射表(Mapping Table)
    目录前言   1.基于范围的分库分表(Range)2.基于哈希的分库分表(Hash)3.基于映射表的分库分表(MappingTable)前言     分库分表是数据库优化中的一项重要技术,它通过将数据分散到多个数据库或表中,以提高系统的处理能力和响应速度。本篇将详细解析三种常见的分库......
  • 万能欧几里得小记
    类欧几里得类欧几里得算法解决这样的问题:\[f(p,q,r,n)=\sum_{x=0}^n[\frac{px+r}{q}]\]可以理解为一条直线下方的整点个数。第一步首先,我们可以将\(r\)对\(q\)取模,从而提取出一个不变量。第二步我们可以继续将\(p\)对\(q\)取模,从而使得\(p,r\)都在\([0,q)......
  • [C++]哈希
    一、概念在顺序结构以及平衡树中,元素关键码(key)与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码(key)的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(log2N),搜索的效率取决于搜索过程中元素的比较次数。理想的搜索方法:可以不经过任何比较,一......
  • 万能可调用对象绑定器CPBind
    背景作为一个C++程序员,经常喜欢写一些代码小工具,有一天写代码用到了std::bind,需要和std::function配合使用,并且需要传递的参数类型也已经固定,所以我就想能不能写一个类让它可以接受任意类型的可调用对象(C函数,成员函数,静态函数,lambda表达式,重载operator()的类对象等),所以写出......
  • Day6 (哈希表)| 454.四数相加II 383.赎金信 15.三数之和 18.四数之和
    454.四数相加II给你四个整数数组nums1、nums2、nums3和nums4,数组长度都是n,请你计算有多少个元组(i,j,k,l)能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0示例1:输入:nums1=[1,2],nums2=[-2,-1],nums3=[-1,2],nums4=[0,2]......