1. 程式人生 > 實用技巧 >等待與通知、掛起與繼續執行、等待執行緒結束和謙讓

等待與通知、掛起與繼續執行、等待執行緒結束和謙讓

字串雜湊

  說得通俗一點,字串雜湊實質上就是把每個不同的字串轉成不同的整數

  為什麼會有這樣的需要呢?很明顯,儲存一個超長的字串和儲存一個超大但是能存的下的整數,後者所佔的空間會少的多,但主要還是為了方便判斷一個字串是否出現過,這是最基礎的部分。並保證字串不同,得到的雜湊值不同,這樣就可以用來判斷一個該字串是否重複出現過。

  當然也很容易想到,如果有不同的字串轉成同一個整數,那麼區分功能就基本廢掉,所以我們需要一個演算法把每個字串轉成唯一的整數。所以字串雜湊演算法就應運而生,雜湊演算法的難點也就在於如何構造一個合適的Hash函式來滿足我們的需求。

  而這裡我們採取的辦法就是將每一個字串看成是一個P進位制的數字,那麼我們將其轉化為十進位制之後模上一個數M之後再對映到相應的陣列中,這就是字串hash(其中一種辦法)

  我們的經驗做法是將P取成131或者13331,將M取為2^64(這時99。99%的情況下是認為不會產生衝突)。此時我們只需對陣列開一個unsigned long long,因為這時超過2^64系統就會自動取模。

  這時我們需要求某一區間的字串時就是用h[r]-h[l-1]*P^(r-l+1)。

程式碼:

#include<iostream>
using namespace std;
typedef unsigned long long ull; 
const int N=1000010,P=131;
int n,m;
char str[N];
ull p[N],h[N];//p陣列用來儲存P的多少次方,h用來對映字串字首的雜湊值 
int get(int l,int r) { return h[r]-h[l-1]*p[r-l+1];//公式計算字串裡面某一子段的雜湊值 } int main() { scanf("%d%d%s",&n,&m,str+1); p[0]=1; for(int i=1;i<=n;i++) { p[i]=p[i-1]*P;//p陣列的初始化 h[i]=h[i-1]*P+str[i];//字首的雜湊值變化 //字首字串的個數增加一就是前面的值乘以P以後加上當前的字元值 } while(m--) {
int l1,r1,l2,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2); if(get(l1,r1)==get(l2,r2)) puts("Yes"); else puts("No"); } return 0; }

由於我們需要求得P^(l-r+1),所以我們開一個p陣列來儲存p的多少次方。