字典树是一种树形结构,优点是利用字符串的公共前缀来节约存储空间。字典树最常用于统计,排序和保存大量的字符串。
字典树一般的操作为两种:
1.将字符串插入到一个集合中。
2.查询一个字符串是否在集合中。
插入操作:
例如要插入字符串“in”。开始时位于根,表示为0号节点,此时设p=0,现在查看p是否有一条标识为i的边连着它的子节点,没有则建立一个新的节点1号节点,此时p=1,将0号节点和1号节点的边标识为i。再往下走看是否又有一条标识为n的边连接着1号节点的子节点,没有则建立一个新的节点2号节点,此时p=2,将1号节点和2号节点的边标识为n,这时字符串“in”就完成了插入,最后将2号节点标识为终点。
查询操作:
假如一个字符串从根节点开始往下找,沿着标识着S[1] -> S[2] -> S[3] … -> S[S.len]的边移动,如果有一个字符找不到或者找完后最后的那个节点未被标识为终点则这个字符串不在集合中。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
int t, b[100005][26], flag, idx, x;
bool c[100005];
void insert(char* a)//插入字符串
{
int t = strlen(a), p = 0;
for (int i = 0; i < t; i++)
{
int x = a[i] - 'a';
if (!b[p][x])//判断p有无被标识为字符a[i]的边连着他的子节点
b[p][x] = ++idx;//没有就建立一个新的节点
p = b[p][x];//有则将该子节点的值赋给p
}
c[p] = 1;//将p号节点标识为终点
return;
}
bool search(char *a)//查询字符串
{
int t = strlen(a), p = 0, s = 0;
for (int i = 0; i < t; i++)
{
int x = a[i] - 'a';
if (!b[p][x])//没有找到p标识为a[i]的边有子节点连着
return false;
p = b[p][x];
}
if (c[p])//判断字符串的最后一个字符在集合中是不是终点
return true;
else
return false;
}
int main()
{
cin >> t >> x;
while (t--)
{
char a[30];
scanf("%s", a);
insert(a);
}
while (x--)
{
char a[30];
scanf("%s", a);
if (search(a))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}