2018-10-26 20:25:42
1455:【例題1】Oulipo
【題目描述】
給出兩個字符串s1,s2((只有大寫字母),求s1在s2中出現多少次。
例如:s1="ABA",s2="ABAABA",答案為2。
【輸入】
輸入T組數據,每組數據輸出結果。
【輸出】
如題述。
【輸入樣例】
3
BAPC
BAPC
AZA
AZAAZAAZA
VEEDI
AVERDXIVYERDLAN
【輸出樣例】
1
3
0
【提示】
1≤s1的長度 ≤104 ,1≤s2的長度 ≤106 。
【題目大意】
其實這道題就是一個哈希的模板題吧,然后我想寫解題報告加深一下印象。
【思路】
我的思路就是哈希的思路(哈哈),然后具體說一下哈希的算法是怎么樣的。
其實,哈希的功能就是解決像這道題目類型的,在一個字符串s2中匹配s1(找出現的位置或者出現的次數)
哈希的大體思想就是將每一段字符串或者大數據用變量直接來表示,這樣只要直接比較兩段字符串的哈希值
就可以直接判斷這兩段字符串或者大數據是不是相等。
第一個問題,怎么用變量表達字符串呢?
我們事先選一個合適的互質的b和h兩個值(b<h),則字符串C=C1C2C3...Cm我們定義的哈希值是:
H[m]=(C1bm-1+C2bm-2+...+Cmb0)%h
那其實只要遞推一下就可以解決了H[k]=H[k-1]*b+c[k];(暫不考慮%的東西)
舉個例子:C=“ABCD”
H[1]=1;
H[2]=1*b+2;
H[3]=1*b2+2*b+3;
H[4]=1*b3+2*b2+3*b+4;
然后對於某一段字符串的哈希值,C‘=“BC”
H[C']=H[3]-H[1]*b2
就是對於C'=Ck+1Ck+2...Ck+n
H[C']=H[k+n]-H[k]*bn
第二個問題,怎么很好很快的算出bn的值?
其實只要先預處理一下就好了,power[n]=power[n-1]*b
第三個問題,怎么比較?
枚舉s2從0開始到m-n(m表示s2的長度,n表示s1的長度),如果哈希值相等則這兩段字符串相等。
然后代碼插上!
#include<bits/stdc++.h> using namespace std; int T; int n,m; int ans; char s1[10000+10],s2[1000000+10]; unsigned long long power[1000000+10]; unsigned long long H[1000000+10]; unsigned long long s,b=27,h=1<<31; //unsigned long long 這是比long long還大的定義,但沒有負值 int main() { power[0]=1; for(int i=1;i<=1000000;i++) power[i]=power[i-1]*b; scanf("%d",&T); while(T--) { scanf("%s%s",s1+1,s2+1); n=strlen(s1+1);m=strlen(s2+1); H[0]=0; for(int i=1;i<=m;i++) H[i]=(H[i-1]*b+(unsigned long long)(s2[i]-'A'+1))%h;//預處理出s2的每個字符前的哈希值 s=0; for(int i=1;i<=n;i++) s=(s*b+(unsigned long long)(s1[i]-'A'+1))%h;//算出s1的哈希值 ans=0; //for(int i=1;i<=m;i++) //cout<<H[i]<<endl; //cout<<s<<endl; for(int i=0;i<=m-n;i++) if(s==H[i+n]-H[i]*power[n]) ans++; printf("%d\n",ans); } return 0; }
