这里我们用到字典树的树形结构存储字符串(单独的小写字母或者单独的大写字母),我们通过一个二维数组来建立这个树的数据结构。
,通常是设一个son[N][26]的二维数组和一个index变量作为计数器,N是一个比较大的数,代表字典树建立时需要用到的节点数,26则表示每个节点最多只有26个分支,即26个字母数。
接下来通过son[i]代表第i个节点,每个节点可以有26条分支son[i][0~25],对应着的当前字符串后一位字符的26种可能性,son[0]节点是树根,树根往下延申但存在其中一个分支时同时这个分支下未开辟节点时为这个申请一个新的节点son[++index],自加让节点分配不会重复分配。
每个节点的26个分支分别存储着这个条分支的下一个节点,接下来把代码展示给大家看一下。
void insert(char str[]) {//往字典树里插入一个新的字符串
int p = 0;//从树根开始
for (int i = 0; str[i]; i++) {//str末尾是‘/0’,此时不满足条件退出循环
int u = str[i] - 'a';//把26个字母分支映射成0~25
if (!son[p][u])son[p][u] = ++index;//son[p][u]==0即该分支下不存在节点时开辟新的节点
p = son[p][u];//p等于下一个节点
}
cnt[p]++;//计算从根节点一直到p节点处的字符串出现过几次
}
查询字符串出现过几次。
int query(char str[]) {//查询字符串函数
int p = 0;//从根节点开始
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a';
if (!son[p][u])return 0;//如果这个分支下没有节点,则返回0;
p = son[p][u];//p变成下一个节点
}
return cnt[p];//如果字符串在字典树出现过,查询cnt数组
}
最后完整的代码
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], index;
char str[N];
void insert(char str[]) {
int p = 0;
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a';
if (!son[p][u])son[p][u] = ++index;
p = son[p][u];
}
cnt[p]++;
}
int query(char str[]) {
int p = 0;
for (int i = 0; str[i]; i++) {
int u = str[i] - 'a';
if (!son[p][u])return 0;
p = son[p][u];
}
return cnt[p];
}
int main(){
int n;
scanf("%d", &n);
while (n--) {
char op[2];
scanf("%s%s", op, str);
if (op[0] == 'I')insert(str);
else cout << query(str) << endl;
}
return 0;
}