字串雜湊

2021-09-11 01:29:02 字數 2587 閱讀 2794

昨天做了一道字串雜湊的題,感覺還好理解。今天的題看了**不知道為什麼,搜來搜去發現不知道的東西還很多,網上找到的東西也都是很零散,書上也沒有系統的講解。

先自己整理一下這些零散的知識:

關於字串涉及到的演算法大概有:hash、kmp、trie、ac自動機等等,現在還都不明白是怎麼回事,這次先研究字串hash。

有乙個帖子說的比較好:所謂字串hash,就是想辦法把乙個字串變成乙個整數。應用的場景一般是字串的查重,如果要在乙個大的字串集合中查詢是否有某乙個字串,常規的比較查詢方法效率會很低,如果每乙個字串都能轉換成乙個整數(最好是唯一的整數)那就快多了。

構造乙個好的hash方法,將乙個字串轉換成乙個整數,就是「字串雜湊演算法」

步驟:1、首先把字串中的每乙個字元轉換成乙個數字,比如把『a』-『z』轉換成1-26。可以表示為 id( s[i] ) = s[i]-『a』+1,注意一般不要把某個字元對映成『0』,如果把『a』對映成0,那在以後就不好區分『b』和『ab』了。

2、經過第1步之後,乙個字串就變成了一串數字,這串數字還要再經過處理,把它對映成乙個整數。對映的方法就是把這串數字當成乙個p進製的數,並把它按照b進製數轉換成十進位制,得到乙個十進位制整數,也就是構造hash函式:

unsigned long long hash[n]

hash[i]=hash[ ]∗p+id(s[i])

這裡定義成unsigned long long,說是利用unsigned long long的範圍自然溢位,相當於自動對2^64−1取模,

並且,這個結果一般還要對某個數取模:

hash[i]=(hash[i−1])∗p+id(s[i]) % mod

其中p和mod均為質數,且有pp 一般可以取:131、13331

舉個例子,乙個字串『abc』: s[ ]= ,將其轉換為數字串『123』

取p為13、mod為101

則:hash[0] = 1

hash[1] = hash[0]*13 + 2 = 15

hash[2] = hash[1]*13 +3 = 97

這樣,字串』abc』就對映成了乙個整數97了,

3、接下來很重要的一點:當得到了乙個字串的hash值之後,如何計算它的某個子串的hash值,這也得需要一系列的推導:

假設有乙個長度為5的字串s: |s|=5,hash函式為:hash[i]=hash[ i-1

]∗p+s[i],則有:

子串『s1』------------------hash[1]=s1

子串『s1s2』---------------hash[2]=s1∗p+s2

子串『s1s2s3』----------- hash[3]=s1∗p2+s2∗p+s3

子串『s1s2s3s4』-------- hash[4]=s1∗p3+s2∗p2+s3∗p+s4

子串『s1s2s3s4s5』----- hash[5]=s1∗p4+ s2∗p3+s3∗p2+s4∗p+s5

現在想計算子串『s3s4』的hash值,子串『s3s4』可以看做是子串『s1s2s3s4』-『s1s2』,那是不是就可以通過『s1s2s3s4』的hash值減』s1s2』的hash值得到呢?下面就來推導:

對於字串『s3s4』,按公式其hash值= s3*p+s4

對比一下 hash[4]和hash[2],可以發現 hash[4]-hash[2]p2就是s3p+s4,這樣子串『s3s4』的hash值就可以通過hash[4]和hash[2]的運算得到,那麼上面相減的計算中hash[2]為什麼要乘以p的2次方,而不是3次方,其他次方呢? 規律就是 『s3s4』 就是(4-3+1)次方

下面推出一般情況:

對於乙個長度為n的字串 s1s2s3s4……sn,已知每乙個hash[i],(1 ≤ i ≤ n)

要計算其中某段長度子串的hash值,子串是『sl……sr』,且 (1 ≤ l ≤ r ≤ n),其公式如下:

hash[sl…sr] = hash[r] - hash[l-1] * p^( r-l+1)^

如果需要取模的話,hash[sl…sr] = (hash[r] - hash[l-1] * p^( r-l+1)^)%mod

1給兩個字串s1,s2,求s2是否是s1的子串,並求s2在s1**現的次數

把s2 hash出來,在s1裡找所有長度為|s2|並計算hash,放入map中查詢

2給n個單詞串,和乙個文章串,求每個單詞串是否是文章串的子串,並求每個單詞在文章**現的次數

把每乙個單詞hash成整數,再把文章的每乙個子串hash成整數,接下來只需要進行整數上的查詢即可。

複雜度:o(|a|2+|s|)o(|a|2+|s|)

用ac自動機可以做到o(|a|+|s|)

3給兩個字串s1,s2,求它們的最長公共子串的長度

將s1的每乙個子串都hash成乙個整數,將s2的每乙個子串都hash成乙個整數。兩堆整數,相同的配對,並且找到所表示的字串長度最大的即可

4給乙個字串s,求s的最長回文子串。

比如abcbbabbc的最長回文子串是cbbabbc,bbabb也是回文串,但不是最長的

先求子串長度位奇數的,再求偶數的。列舉回文子串的中心位置,然後二分子串的長度,直到找到乙個該位置的最長回文子串,不斷維護長度最大值即可。

複雜度:o(|s|∗log|s|)

字串雜湊

參照演算法筆記p109,甲級1039 先假設字串均由大寫字母a z構成。在這個基礎上,不妨把a z視為0 25,這樣就把26個大寫字母對應到了26進製中。接著,按照將26進製轉化為10進製的思路,由進製的轉換結論可知,在進製轉換過程中,得到的10進製肯定是唯一的,由此便可實現將字串對映為整數的需求 ...

字串雜湊

給定乙個長度為n的字串,再給定m個詢問,每個詢問包含四個整數l1,r1,l2,r2,請你判斷 l1,r1 和 l2,r2 這兩個區間所包含的字串子串是否完全相同。字串中只包含大小寫英文本母和數字。輸入格式 第一行包含整數n和m,表示字串長度和詢問次數。第二行包含乙個長度為n的字串,字串中只包含大小寫...

字串雜湊

字串雜湊就是將乙個字串對映成乙個p進製的數,然後用字首記錄下來,當你查詢某個字串的雜湊值時,只要用字首相減就可以了。通常p取131或者13331來盡可能減少衝突,同時用unsigned long long值過大自動溢位避免手動取模 eg s abacbdab h是字首和,v是字元的值 h 1 v a...