Hash——字符串匹配(求s1在s2中出现的次数)
題目描述:
這是一道模板題。
給定一個字符串?A 和一個字符串?B ,求?B 在?A ?中的出現次數。A?和?B中的字符均為英語大寫字母。
求A?在?B 中出現了幾次。(可重疊)
樣例輸入:
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
樣例輸出:
1
3
0
首先要知道什么是字符串hash(滾動哈希):
單哈希可以O(m)的時間計算長度為m的字符串的哈希值,但對于本題,總的時間復雜度沒有改觀。時間會爆。
這時我們就需要一個叫做滾動哈希的優化技巧。
我們選取兩個合適的互質常數b和h(b<h),假設字符串C=c1c2……cm,那么我們定義哈希函數:H(C)=(c1bm-1+c2bm-2+……+cmb0) mod h 。
正常數字是十進制的,這里b是基數,相當于把字符串看做是b進制數。
這一過程是遞推計算的,設H(C,k)為前k個字符構成的字符串的哈希值,則:(以下均不考慮取模的情況)
H(C,k+1)=H(C,k)× b + ck+1
字符串哈希,通常題目要求的是判斷主串的一段字符串與另一個匹配串是否匹配,即判斷字符C=c1c2……cm從位置k+1開始的長度為n的子串C'=ck+1ck+2……ck+n的哈希值與另一匹配串S=s1s2……sn的哈希值是否相等,則:
H(C')=H(C,k+n) - H(C,k) × bn
于是我們只要預求得b,就能在O(1)時間內得到任意字符串的字符串的子串哈希值,從而完成字符串匹配,那么上述字符串匹配問題的算法復雜度就為O(n+m)。
在實現算法時,可以利用32位或64位無符號整數計算hash值(如:unsigned long long),并取h=232或h=264,通過自然溢出省去取模運算。
——By《一本通》
那么本題就可以用上述方式AC了(書上代碼有bug,需自己改動)
AC代碼如下:
#include<cstring>#include<cstdio> using namespace std; #define ULL unsigned long long #define K 103 int N; char s1[1000005], s2[1000005]; ULL f[1000005],l1,l2,t; ULL a[1000005]; ULL get(int x,int y) {return f[y]-f[x-1]*a[y-x+1]; } int main() {//freopen("字符串匹配(求s1在s2中出現的次數).in","r",stdin);//freopen("字符串匹配(求s1在s2中出現的次數).out","w",stdout); scanf("%d",&N);a[0]=1;for(int i=1;i<=1000000;++i)//預處理出a^na[i]=a[i-1]*K;for(int i=1;i<=N;++i){int ans(0);t=0;scanf("%s%s",s2+1,s1+1);l1=strlen(s1+1);l2=strlen(s2+1);for(int j=1;j<=l1;++j)f[j]=f[j-1]*K+(s1[j]-'A');//計算主串的滾動哈希值 for(int j=1;j<=l2;++j)t=t*K+(s2[j]-'A');//計算匹配串的哈希值 for (int j=1;j+l2-1<=l1;++j){if(get(j,j+l2-1)==t)//枚舉起點為i,長度為n的子串,判斷與匹配串是否匹配 ans++;}printf("%d\n",ans);//輸出 }return 0; }
?
轉載于:https://www.cnblogs.com/lck-lck/p/9588740.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Hash——字符串匹配(求s1在s2中出现的次数)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: _reincarnation
- 下一篇: html-head-body