KMP,Hash,Trie学习笔记
KMP,Hash,Trie学习笔记
今天我们来讲下字符串更深入点的内容,KMP,Hash,Trie。
KMP算法
我也并不是很懂,本质上,记住怎么用和板子可以了。
Code for KMP:
int j=0;
for(int i=1;i<=n;i++){
while(j&&a[j+1]!=a[i]) j=kmp[j];
if(a[j+1]==a[i]) j++;
kmp[i]=j;
}
练习题
Hash 算法:
OI Wiki
字符串哈希是一种可以用于快速比较字符串的算法,通过加上上一项,再乘上 \(base\),接着模上 \(mod\) 而加密成一个神秘的数字,且无法回推, \(mod\) 常取一些大质数,如 \(998244353\),\(1000000007\) 等。\(base\) 常取 \(13331\) 等,通过类似前缀和查询的方式查询字符串加密后的值。
Code for Hash:
void build(){
int base=13331,mod=998244353;
for(int i=1;i<=n;i++){
hash[i]=(hash[i-1]*base+s[i])%mod;
pw[i]=(pw[i-1]*base)%mod;
}
}
int query(int l,int r){
if(l>r) return 0;
return ((hash[r]-hash[l-1]*pw[r-l+1])%mod+mod)%mod;
}
练习题:
Hash模板
Hash思维题
Hash较难题1
Hash较难题2
Trie 算法:
OI Wiki
Trie 又名字典树,是一种树形数据结构,以字符为边,节点按序号排列,插入时,若有前缀相同的子树,便将除前缀外的部分插入在该子树下面。查询时,按字符遍历,走与字符相同的边即可。
Code for Trie
int tr[3000005][27],tot=1,cnt[3000005];
void insert(string str){
int p=1;
for(int i=0;i<str.size();i++) {
int u=str[i]-'a';
if(!tr[p][u]) tr[p][u]=++tot;
p=tr[p][u];
}
}
int query(string str){ //查询以str为前缀的字符串数量
int p=1;
for(int i=0;i<str.size();i++){
int u=str[i]-'a';
if(!tr[p][u]) return 0;
p=tr[p][u];
}
return cnt[p];
}
练习题:
小扩展:01 Trie
01 Trie 本质上根 Trie 差不多,只是边权变成了 0 或 1,通常出理二进制问题,如最大异或和等。
Code for 01Trie
int tr[3000005][2],cnt[3000005],tot=1;
void insert(int x){
int p=1;
for(int i=30;i>=0;i--){
int u=x>>i&1;
if(!tr[p][u]) tr[p][u]=++tot;
p=tr[p][u];
cnt[p]++;
}
}
int query(int x,int k){//求当中子序列异或和 >=k 的数量
int p=1,ans=0;
for(int i=30;i>=0;i--){
int u=x>>i&1,v=k>>i&1;
if(v==1) p=tr[p][u^1];
else{
ans+=cnt[tr[p][u^1]];
p=tr[p][u];
}
}
ans+=cnt[p];
return ans;
}
浙公网安备 33010602011771号