给出一个电话列表,如果列表中存在其中一个号码是另一个号码的前缀这一情况,那么就称这个电话列表是不兼容的。
假设电话列表如下:
·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
思路:每次将输入的串写入字典树,用一个vis数组标记一下当前串在字典树对应路径的终点位置,记为true。
如果当前串将其每个字符依次插入字典树时发现有标记过的点,则说明当前串的这个前缀是之前的某个字符串,让当前串的hasSubStr记为true(即:不合法),即当前串的前缀包含前面的串,则不合法;
并且要求当前串不能是前面的串的前缀,即:至少有一个结点时新的,isNew=true为合法。
如果同时满足以上两个判断都合法,则当前串合法,若最后n个串都合法,说明n个串之间无前缀关系,兼容,cout<<"YES"<<endl;否则cout<<"NO"<<endl;
完整代码:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int maxn=1e5+5;
int son[maxn][10],idx;
bool vis[maxn];
bool insert(string s)
{
bool HasSubstr=false,isNew=false;
int p=0;
for(int i=0;i<s.size();i++){
int x=s[i]-'0';
if(!son[p][x]){
isNew=true;
son[p][x]=++idx;
}
p=son[p][x];
if(vis[p]) HasSubstr=true;
}
vis[p]=true;
return !HasSubstr&&isNew;
}
int main()
{
int t;
cin>>t;
while(t--){
int n;
cin>>n;
memset(son,0,sizeof son);
memset(vis,false,sizeof vis);
bool flag=true;
idx=0;
while(n--){
string s;
cin>>s;
if(!insert(s)) flag=false;
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}