原题链接
给出一个电话列表,如果列表中存在其中一个号码是另一个号码的前缀这一情况,那么就称这个电话列表是不兼容的。
假设电话列表如下:
·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
> 分析
:看到前缀,肯定能想到前缀树(字典树)。
起初是这样想的:字符串的前缀肯定是比自身短的,于是先按长度由小到大排序,之后在插入的时候判断,是否当前的位置是前面某串的结束位置。
如果是,那么前面那个字符串一定是当前字符串的前缀(如果是前面有前缀字符串的话,那当前的字符串一定会循着前面那前缀字符串的路径走,所以前缀字符串的结束位置一定会被当前字符串经过,如此便可判断。然后由于数组大小原因wa了,最后才改过来。。
然后又想了想(
查了查…),发现也可以这样做:存在前缀,无非有两种情况:
1、当前字符串是别的字符串的前缀;2、别的字符串是当前字符串的前缀。
那么,直接在插入的时候判断就可以了:如果始终没有开辟新的路径,那么该字符串是别的字符串的前缀;如果该字符串经过了前面字符串的结束位置,那么前面字符串就是当前字符串的前缀(相当于第一种排过序的思路)。
法1code:
#include<bits/stdc++.h>
using namespace std;
string a[10010];
int tree[100001][11],cnt,t,flag;
int T,n;
bool isEnd[100010];
int cmp(string a,string b){
return a.size()<b.size();
}
int insert(string a){ //插入、判断;
int root=0;
for(int i=0;i<a.size();i++){
t=a[i]-'0';
if(!tree[root][t]) tree[root][t]=++cnt; //另辟路径;
root=tree[root][t];
if(isEnd[root]==true) {flag=1;return 0;} //经过了前面字符串的结束位置;
}
isEnd[root]=true; //标记结束位置;
return 0;
}
int main(){
cin>>T;
while(T--)
{ //多组数据时,数组和变量的的初始化一定不要忘记;
for(int i=0;i<=100010;i++) isEnd[i]=false;
for(int i=0;i<100001;i++)
for(int j=0;j<=9;j++)
tree[i][j]=0;
cnt=0;
flag=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n,cmp); //按长度将字符串排序;
for(int i=1;i<=n;i++){
insert(a[i]); //插入;
}
if(flag==0) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
法2code:
#include<bits/stdc++.h>
using namespace std;
string a[10010];
int tree[100001][11],cnt,t,flag;
int T,n;
bool isEnd[100010];
int insert(string a){
int root=0;
int flag1=0;
for(int i=0;i<a.size();i++){
t=a[i]-'0';
if(!tree[root][t]) flag1=1,tree[root][t]=++cnt; //如果新辟路经了,记录一下;
root=tree[root][t];
if(isEnd[root]==true) {flag=1;return 0;} //如果经过了前面串的结束位置,说明前面串是该串的前缀,返回;
}
if(flag1==0) {flag=1;return 0;} //始终没有新辟路经,说明是前面串的前缀,返回;
isEnd[root]=true; //标记结束位置;
return 0;
}
int main(){
cin>>T;
while(T--)
{ //初始化;
for(int i=0;i<=100010;i++) isEnd[i]=false;
for(int i=0;i<100001;i++)
for(int j=0;j<=9;j++)
tree[i][j]=0;
cnt=0;
flag=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
insert(a[i]);
}
if(flag==0) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
如果有不对或者不明白的地方欢迎留言评论.