(字典树应用)
小学生一发
一道比较裸的字典树,巩固一下这个数据结构。
后缀字符串
题目描述:
一天蒜头君得到
n
n
n个字符串
s
i
s_i
si, 每个字符串的长度都不超过10。
蒜头君在想,在这 n n n个字符串中,以 s i s_i si为后缀的字符串有多少个呢?
输入:
第一行输入一个整数
n
n
n。(n<=105)
接下来
n
n
n行,每行输入一个字符串
s
i
s_i
si。
输出:
输出
n
n
n个整数,第
i
i
i个整数表示以
s
i
s_i
si为后缀的字符串的个数。
解析
题意很简单,直接暴力显然超时。这就需要一个很牛逼的数据结构——字典树。什么是字典树可以百度下,大佬们写得很详细(https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html)。
既然是求后缀,那么只需要把字符串倒着插入就行了。代码其实就是一个字典树的板子。(?)
AC代码:
// 小学生一发的刷题之路
// 数据结构-字典树
//
//
//
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <deque> //双向队列;
#include <cmath>
#include <set>
#include <stack>
#include <map>
#include <vector>
#include <cstdlib>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double PI=acos(-1.0);
const double eps=1e-8;
const double e=exp(1.0);
const int maxn=1e5+5;
const int maxm=1e6+5;
const ll mod=1e9+7;
const int INF=1e8;
template<class T>
void read(T &ret){ //快速输入模版;
ret=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ret=ret*10+c-'0';
c=getchar();
}
ret*=f;
}
int n,trie[maxm][26],sum[maxm],tot=0;
string str[maxn];
void insert(string str){
int root=0,len=str.length();
for(int i=len-1;i>=0;i--){ //将字符串倒着插入字典树;
int id=str[i]-'a';
if(!trie[root][id]){
trie[root][id]=++tot;
}
root=trie[root][id];
sum[root]++; //统计后缀出现的次数;
}
}
int find(string str){
int root=0,len=str.length();
int ok=1;
for(int i=len-1;i>=0;i--){
int id=str[i]-'a';
if(!trie[root][id]){ //未出现的字符结束搜索;
ok=0;
break;
}
root=trie[root][id];
}
if(ok){
return sum[root];
}
return 0;
}
int main()
{
memset(trie,0,sizeof(trie));
memset(sum,0,sizeof(sum));
scanf("%d",&n);
for(int i=1;i<=n;i++){
cin>>str[i];
insert(str[i]);
}
for(int i=1;i<=n;i++){
printf("%d\n",find(str[i]));
}
return 0;
}
新的开始,每天都要快乐哈。