【前缀判断】 电话列表
传送门
题意
给定\(N\)个表示电话号码的字符串,判断这\(N\)个字符串中是否存在其中一个为另一个的子串,只要存在就输出\(NO\),否则输出\(YES\)
数据范围
\(1\leq T\leq 40\)
\(1\leq N\leq 10^{4}\)
题解
建立一个字典树,在插入字符串的同时进行如下判断
-
判断树中有没有当前插入串的子串
-
如果当前树插入过程中没有添加新的边则说明了这个字符串是其他串的子串
记录每个字符串的结尾用来判断串的结尾
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
const int N=1e5+10;
int n;
int trie[N][10],tot=1;
bool rec[N];
int _;
bool insert(char s[])
{
bool ok=false,has_find=false;
int p=1;
for(int i=0;s[i];i++){
int c=s[i]-'0';
if(!trie[p][c])
{
trie[p][c]=++tot;
ok=true; // 不是别的串的子串
}
p=trie[p][c];
if(rec[p]) has_find=1; // 别的串是当前串的子串
}
rec[p]=true;
return ok && !has_find;
}
void solve()
{
memset(trie,0,sizeof trie);
memset(rec,0,sizeof rec);
tot=1;
scanf("%d",&n);
bool ok=true;
char s[20];
rep(i,0,n){
scanf("%s",s);
if(!insert(s))
ok=0;
}
if(ok) puts("YES");
else puts("NO");
}
int main(){
cin>>_;
while(_--) solve();
}