求字符串(单词)在文本中出现与否和出现的次数---Trie树(字典树)算法

字典树模板
字典树模板
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
inline int read();
int next_[500000][26];//p[节点的数量][当前节点的分支数量]
int f[500000];//表示是否以当前节点结尾
char s[30];//词组
int cnt=0;//节点的个数
void insert_(int len,int n){//插入当前单词
int now=0;//当前位置
for(int i=1;i<=len;i++){
    int x = s[i] - 'a';
    if(!next_[now][x]){//当前字母没有出现过就加上它
        next_[now][x]=++cnt;
    }
    now = next_[now][x];//更新当前节点位置
}
f[now]++;//以当前节点结尾的单词数量加一
}
bool search_(int len,int n){//查找当前单词
int now=0;
for(int i=1;i<=len;i++){
    int x = s[i] - 'a';
    if(!next_[now][x]){
        return false;//没找到某个字母返回false
    }
    now = next_[now][x];
}
if(f[now]!=0){//当前节点被标记为单词结尾返回true
    return true;
}
else return false;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
    scanf("%s",s+1);
    int len=strlen(s+1);
    insert_(len,i);//插入单词
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
    scanf("%s",s+1);
    int len=strlen(s+1);
    if(search_(len,n)){//search单词
        printf("存在当前单词\n");
    }
    else {
        printf("不存在当前单词\n");
    }
}
return 0;
}

字典树模板题

例2(求解一个字符串它的前缀字符串有多少个以及以它为前缀的字符串有多少个)

Secret Message G
思路:分两步走
1.当找到当前字符串的最后一个字母还没有找到这个字符串结尾(即当前字符串比字典树里有的字符串还要长),直接求解它前面有多少个前缀就可以了
2.当这个字符串最后一位小于字典树的最大长度,我们求出它前面的字符串的和减去以当前位置结尾的字符串的个数加上后面的以当前字符串为前缀的字符串个数就可以了 ans-f[now]+c[now]

#include<bits/stdc++.h>
using namespace std;
int next_[500010][2];
int c[500010];//有多少个单词经过当前字母
int f[500010];//统计以当前字母结尾的单词个数
int p[500010];
int cnt=0;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
void insert_(){
int n;
scanf("%d",&n);
int now=0;
int tot=1;
int flag=0;
for(int i=1;i<=n;i++){
    int x= read();
    if(!next_[now][x]){
        next_[now][x]=++cnt;
    }
    now = next_[now][x];
    c[now]++;
}
   f[now]++;
}
int search_(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
    p[i]=read();
}
int ans = 0;
int now=0;
for(int i=1;i<=n;i++){
    int x = p[i];
    if(!next_[now][x]){
        return ans;//第一步
    }
    now = next_[now][x];
    ans += f[now];
}
return ans-f[now]+c[now];//第二步
}
int main(){
int m = read(),n = read();
for(int i=1;i<=m;i++){
    insert_();
}

for(int i=1;i<=n;i++){
    int res = search_();
    printf("%d\n",res);
}
return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值