1. 程式人生 > 其它 >【字串】字串雜湊

【字串】字串雜湊

目錄

字串雜湊

雜湊

雜湊就是將所要處理的資料轉化成數字,且這個數字能唯一地去對應上這個資料,若這個數字對應上了多個數字,則稱作雜湊衝突。比如\(K_{1}!=K_{2}\),但\(hash(K_{1})=hash({K_{2}})\)

字串雜湊

概念:字串雜湊是指將一個任意長度的字串對映成一個非負整數,並且衝突的概率幾乎為0.

字串的雜湊衝突:

衝突:兩個字串不相等,但是他們的p進位制數相同

字串雜湊的思想

將字串看成一連串的數字,字串裡的每一位看成在某一個特定位置上的單獨的數字,並對這個數字賦予一定的權值,設為P(也用P來指說字串可以看成是一個P進位制數),這時候我們可以將由代表這個字串的P進位制數轉化成十進位制數, 並向一個固定的數M取餘(M代表的是雜湊值的範圍).

  • P一般取131或者13331,如果題目的字串僅有小寫字母,可以考慮取26.
  • M可以設定成是2的64次方(只需unsigned long long),一方面,超出上界(溢位)後,數值會自動從0開始計算,這種天然的取餘操作相比於再去使用mod取餘操作會更高效.(面向一些大質數取餘,比如1E9,能減少雜湊衝突的概率(數論的知識,還不太懂)),另一方面,unsigned long long 具有資料範圍大,能容納的雜湊值更多.

例子: 我們將a~z一一與1到26對應

\(hash("abcb")=a*P^{3}+b*P^{2}+c*P^{1}+b*P^{0}\)

字串雜湊的基本運算

  • 已知某一字串的雜湊值,在其字串的尾巴繼續添置一個字母,求新組成的字串的雜湊值.

\(hash("abcb"+'d') =hash("abcbd")=(a*P^{4}+b*P^{3}+c*P^{2}+b*P^{1}+d=hash("abcb")*P+d)\%\space mod\)

  • 進而我們有,已知字串S和字串T的雜湊值,求S+T的雜湊值

    \[H(S+T)=(H(S)\times P^{len-of-T}+H(T))\% \space mod$$​ \]\[H(T) =(H(S+T)-H(S)*P^{len-of-T})\%\space mod$$​​ \]

AcWing 138. 兔子與兔子

#include <bits/stdc++.h>
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define pi acos(-1.0)
#define PII pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
using namespace std;
int n,m;
const int P=131,N = 1E6+10;
ull h[N],mul[N];
void pre_work(string s)
{
	MEM(h,0);
	mul[0]=1;
	repd(i,1,s.length())
	{
		h[i]=h[i-1]*P+(s[i-1]-'a'+1);		
		mul[i]=mul[i-1]*P;
	}
}
int main()
{
	string dna;
	int t;
	cin>>dna>>t;
	pre_work(dna);
	while(t--)
	{
		int l1,r1,l2,r2;
		cin>>l1>>r1>>l2>>r2;
		if( (h[r1]-h[l1-1]*mul[r1-l1+1]) == (h[r2]-h[l2-1]*mul[r2-l2+1]) )
	        cout<<"Yes"<<endl;
	    else cout<<"No"<<endl;
	}
    return 0;
}