字典树


tire 字典树

先来个模板

142. 前缀统计 - AcWing题库

什么是字典树呢?

就是存字典的树嘛,差不多的赶脚。

确实是将所有字符存入其中,方便查找(多是查找前缀)。怎么存捏?如下图

trie

建树

差不多是这个意思,但并非是把所有字符的空间给开出来,这就要讲到如何建树了。

void insert()
{
   int root = 0;
   for (int i = 0; str[i]; i ++)
   {
   	int s = str[i] - 'a';
   	if(!son[root][s]) son[root][s] = ++ idx;
   	root = son[root][s];
   }
   cnt[root]++;
}

root 节点设为0。son{ root }{ s }表示root这个节点上的s的编号idx。倘若这个点没有被创建,那就 son{ root }{ s } = ++ idx; 感觉这个 root 有并查集那味儿。存储他儿子的编号,便于查找。这时候就有读者要问,这个cnt{ N }是干嘛用的呢?答案是记录以这个点为结尾的数量。在搜前缀时,不一定只有一个字符从这里结束,所以要记录一下数量。

搜索

int search()
{
	int root = 0, res = 0;
	for(int i = 0; str[i]; i ++)
	{
		int s = str[i] - 'a';
		if(!son[root][s]) break;
		root = son[root][s];
		res += cnt[root];
	}
	return res;
}

如果说下面没有节点了就直接break掉。并且这里cnt数组派上用场了。res每次加一个cnt{ root }.最后返回答案。

2022-5-12 21:09:37

进阶

AcWing 161. 电话列表 - AcWing

给出一个电话列表,如果列表中存在其中一个号码是另一个号码的前缀这一情况,那么就称这个电话列表是不兼容的。

假设电话列表如下:

  • Emergency 911
  • Alice 97 625 999
  • Bob 91 12 54 26

在此例中,报警电话号码(911)为 Bob 电话号码(91 12 54 26)的前缀,所以该列表不兼容。

输入格式

第一行输入整数 t,表示测试用例数量。

对于每个测试用例,第一行输入整数 n,表示电话号码数量。

接下来 n 行,每行输入一个电话号码,号码内数字之间无空格,电话号码不超过 10 位。

输出格式

对于每个测试用例,如果电话列表兼容,则输出 YES

否则,输出 NO

数据范围

1≤t≤40,
1≤n≤10000

输入样例:

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346

输出样例:

NO
YES

跟模板差不多,只不过在搜的时候要一个一个搜,并且它并非求前缀的数量,所以用bool判断就好了。

#include
#include
#include
using namespace std;

#define N 500010
#define M 1000010

int n, m, f;
int son[N][30], idx, cnt[N], T;
char str[M][15];

void insert(char *s)
{
	int root = 0;
	for (int i = 0; s[i]; i ++)
	{
		int st = s[i] - '0';
		if(!son[root][st]) son[root][st] = ++ idx;
		root = son[root][st];
		cnt[root]++;
	}
	
}

bool search(char *s)
{
	int root = 0;
	for(int i = 0; s[i]; i ++)
	{
		int st = s[i] - '0';
		if(cnt[son[root][st]]==1) return false;
		root = son[root][st];
	}
	return true;
}

int main()
{
	scanf("%d", &T);
	while(T --)
	{
		f=0;
		idx=0;
		memset(son[0],0,sizeof son);
        memset(cnt,0,sizeof cnt);
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf("%s", str[i]);
			insert(str[i]);
		}
		for (int i = 0; i < n; i++)
		{
			if(search(str[i]))
			{
				f=1;
				break;
			}
		}
		if(f == 1) puts("NO");
        else puts("YES");
	}
	
	return 0;
}
	

2022-5-12 21:34:32

相关