字符串Hash 字符比较(O1)

可通过比较区间字符串Hash值来判断两个字符串是否相等:

base类似于进制131就可以,用mod来余除或者unsigned long long 自动余除.

区间Hash值计算 prea[l~r]=prea[r]-prea[l-1]*pre[r-l+1]. prea代表区间累成加a[i]的结果pre[r-l+1]代表还要乘多少才能让prea[r]和prea[l]同位数;类似十进制乘法。

用Hash来过kmp模板题:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N=1e6+10;
const int mod=1e9+7;
int base=131;
int n,m;
string a,b;
int preb[N];
int pre[N];
int HashA;
void init()
{
	HashA=0;
	for(int i=1;i<=n;i++)
	{
		HashA=(HashA*base%mod+a[i])%mod;
	}
	pre[0]=1;
	for(int i=1;i<=m;i++)
	{
		
		preb[i]=(preb[i-1]*base%mod+b[i])%mod;
		pre[i]=pre[i-1]*base%mod;
	}
	
}
void solve()
{
	cin>>n>>a>>m>>b;
	a=" "+a;
	b=" "+b;
	init();
	int f=0;
	for(int i=1,j=n;j<=m;j++,i++)
	{
	
		if((preb[j]-preb[i-1]*pre[j-i+1]%mod+mod)%mod==HashA)
		{
			if(f++) cout<<" ";
			cout<<i-1;	
		}
	}
	if(!f)cout<<-1<<" "<<-1<<endl;
}
signed main()
{
    IOS
//    int _;cin>>_;while(_--)
    solve();
    return 0;
}

Problem - J - Codeforces

选择一段区间翻转后是否能让这个字符串变成回文串

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N=1e5+10;
const int mod=1e9+7;
int base=131;
int n;	
string s;
int prea[N],preb[N],pre[N];
void init()
{
	pre[0]=1;
	for(int i=1;i<=n;i++)
	{
//		正向哈希值 
		prea[i]=(prea[i-1]*base%mod+(s[i]-'a'))%mod;
//		反向哈希值
		preb[n-i+1]=(preb[n-i+2]*base%mod+(s[n-i+1]-'a'))%mod;
//		预处理区间哈希值 
		pre[i]=(pre[i-1]*base)%mod;
	}
}
int getHashA(int l,int r)
{
	return (prea[r]-prea[l-1]*pre[r-l+1]%mod+mod)%mod;
}
int getHashB(int l,int r)
{
	return (preb[l]-preb[r+1]*pre[r-l+1]%mod+mod)%mod;
}
int getA1(int x)
{
//	反向Hash(1~x)*pre[n-x]+正向Hash(x+1~n)
	return (getHashB(1,x)*pre[n-x]%mod+getHashA(x+1,n))%mod;  
}
int getB1(int x)
{
//	反向Hash(n~x+1)*pre[x]+正向Hash(1~x)
	return (getHashB(x+1,n)*pre[x]%mod+getHashA(1,x))%mod;
}

int getA2(int x)
{
//	正向Hash(1~x-1)*pre[n-x+1] +反向Hash(n~x);
	return (getHashA(1,x-1)*pre[n-x+1]%mod+getHashB(x,n))%mod;
}
int getB2(int x)
{
//	正向Hash(x~n)*pre[x-1] + 反向Hash(1~x-1)
	return (getHashA(x,n)*pre[x-1]%mod+getHashB(1,x-1))%mod; 
}

void solve()
{

	cin>>s;
	int l=0,r=(int)s.length()-1;
	while(l<=r)
	{
		if(s[l]!=s[r]) break;
		l++,r--;	
	} 
	if(l>=r)
	{
		cout<<"1 1"<<endl;
		return ;
	}
	string ss="";
	for(int i=l;i<=r;i++) ss+=s[i];
	s=ss;
	n=s.length();
	s=" "+s;
	init();
//	左边定住枚举右边 
	for(int i=2;i<=n;i++)
	{
		if(getA1(i)==getB1(i))
		{
			cout<<l+1<<" "<<l+i<<endl;
			return;
		}
	}
//	右边定住枚举左边
	for(int i=n-1;i>=1;i--)
	{
		if(getA2(i)==getB2(i))
		{
			cout<<l+i<<" "<<r+1<<endl;
			return;	
		}	
	}
	cout<<-1<<" "<<-1<<endl; 
}
signed main()
{
    IOS
//    int _;cin>>_;while(_--)
        solve();
    return 0;
}
/*

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值