字串學習筆記
阿新 • • 發佈:2020-07-20
雜湊
- 雜湊理解起來就相當於用一種對映方式,以實現快速對比字串或者其他東西(比如圖)的功能,有時候利用技巧還能實現字典序大小的比較或者反對映操作。
- 其思想是非常重要而且容易理解的,關鍵在於hash方法以及程式設計上的技巧。
實現方法
- 字首和是hash的常見用法
方法一
#include <bits/stdc++.h> using namespace std; const int maxn=4e5+100; const int base=233; char s[maxn]; int poww[maxn],hash[maxn]; int main(){ while(cin>>s+1){ int len=strlen(s+1); poww[1]=233; for(int i=2;i<=len;i++) poww[i]=poww[i-1]*base; hash[1]=s[1]; for(int i=2;i<=len;i++) hash[i]=hash[i-1]*base+s[i]; } }
方法二
- 把字串變成數字
#define ull unsigned long long
ull gethash(string s){
ull tmp=0;
for(int i=0;i<s.size();i++)
tmp=tmp*233+(s[i]-'a');
return tmp;
}
一道例題
題目
已知字串A與B,有n組詢問,每次詢問給l,r,s,t,要求O(1)判斷A[l…r]與B[s…t]是否相同。
題解
- 既然已經求得兩個字串的hash陣列,就直接取A[l..r]的雜湊值與B[s…t]的雜湊值進行比較即可。
- 那麼如何更加方便的比較呢?
- 我們使用 \(hash[i]=hash[i-1]*10+s[i]\) 的方法進行雜湊得雜湊陣列\(hasha,hashb\)。
- 然後我們發現一個問題:
- 舉一例子:
\(s1: 1 2 3 4 5 1\)
\(s2: 2 3 4 1 1 2\)- \(s1[2…4]\) 與 \(s2[1…3]\) 是相同的,但我們發現,\(hasha[4]-hasha[1]\)與\(hashb[3]-hashb[0]\)並不相同,為什麼呢?
- 回憶我們的雜湊過程,發現我們要乘上一個 \(poww[i]\),這樣我們求出來的才是真正的雜湊,即\(hash[r]-hash[l-1]*pow[i]\)
code
while(n--){
cin>>l>>r>>s>>t;
len=r-l+1;
if(hasha[r]-hasha[l-1]*poww[len] == hashb[s]-hahsb[t-1]*poww[len])
puts("YES");
else puts("NO");
}
再來幾道例題
manachar
普及知識
- 迴文串:abcba(√),abba(√),abda(×)(就是正著看和倒著看相同的串)
- 子串≠子序列(子串是連續的,子序列可不連續)
一道例題
求一個字串中最長迴文子串長度。
例:字串:abbababa 最長迴文子串:ababa
題解
- manacher是一種暴力的優化,可以用O(n)的時間解決上述問題,但是我真的沒怎麼見過這玩意派上用場
- 可以學一下回文自動機,那個的作用要比這個大得多...
- 因為偶迴文串比較難處理(不是以某個字元為中心),所以首先我們要通過在每個相鄰字元中間插入一個相同的字元(比如’|’,一定要是沒有出現過的),這樣預處理操作一發後我們會發現所有的迴文串都是奇迴文串,並且它也不會影響答案。
- 把預處理後的字串叫做S
- 最後的出來的答案就是 S的最長迴文子串長+1
- 複雜度O(n)也是容易理解的,因為R只有一次從1到n,以及i只有一次從1到n,而且二者是並列關係。
- 此種演算法心中有印象即可,十分不常考。
code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e8+100;
char a[maxn<<1];
int f[maxn<<1];
int main(){
int cnt=0;a[0]='~';a[++cnt]='|'; char ch; int ans=0;
while((ch=getchar())>='a' && ch<='z') a[++cnt]=ch,a[++cnt]='|';
for(int i=1,r=0,mid=0;i<=cnt;i++){ //mid中心,i現在的點,f[]半徑
if(i <= r) f[i]=min(f[mid*2-i],r-i+1);
while(a[i-f[i]]==a[i+f[i]]) f[i]++;
if(f[i]+i>r) r=f[i]+i-1,mid=i;
if(f[i]>ans) ans=f[i];
}
printf("%d\n",ans-1);
return 0;
}
推薦例題
有興趣可以做一做洛谷板子題