这道题目是个典型的字典树题目,不断的数字串,并判断是不是有前缀出现,需要注意的是:由于输入的串不一定会按长度排序,所以如果某个数字串的前缀出现在该数字串的后面,那么就会出现错误。我们可以这样,对输入的串进行排序,不过这样太麻烦了。考虑一下即使某个串在其子串前先出现,它还是会沿着子串的路径走,当子串出现的时候,我们可以这样判断:当数字串全部插入进去的时候,我们判断是不是有其它子串走过这条路,如果有,那么必然出现重复的情况,这样我们也就很容易的得出正确的答案。
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std ;
#define MAXN 4000000
struct Trie{
int next[10] ;
int cnt ;
}trie[MAXN];
void initTrie(Trie &t){
for(int i = 0 ; i < 10 ; i++)
t.next[i] = 0 ;
t.cnt = 0 ;
}
char readl[15] ;
int ncount ;
int order ;
void init(){
for(int i = 0 ; i <= ncount ; i ++){
initTrie(trie[i]) ;
}
ncount = 0 ;
order = 0 ;
}
int insert(char * a , int nx){
if( *a ){
if(trie[nx].cnt != 0){
if(trie[nx].next[*a - '0'] == 0){
trie[nx].next[*a - '0'] = ++ncount ;
}
insert(a + 1 , trie[nx].next[*a - '0'] ) ;
return trie[nx].cnt ;
}
else{
if(trie[nx].next[*a - '0'] == 0){
trie[nx].next[*a - '0'] = ++ncount ;
}
return insert(a + 1 , trie[nx].next[*a - '0'] ) ;
}
}
else{
if(trie[nx].cnt != 0)
return trie[nx].cnt ;
trie[nx].cnt = ++ order ;
//注意当字符串为排序的时候,短的在后插入的时候,要判断当前的路是否有其它字符串走过
for(int i = 0 ; i <= 9 ; i ++){
if(trie[nx].next[i] != 0){
return 1 ;
}
}
return 0 ;
}
}
int main(){
int t ;
int n ;
scanf("%d" , &t) ;
while(t--){
scanf("%d" , &n) ;
init() ;
int flag = 0 ;
for(;n--;){
scanf("%s" , readl) ;
if(!flag){
flag = insert(readl , 0) ;
}
}
if(flag){
printf("NO\n") ;
}
else{
printf("YES\n") ;
}
}
return 0 ;
}
POJ1056这道题目于上面的类似,不过这道题目比上面的要容易的多,不需要考虑数字串的长度问题,数据也弱的多。改一下上面的输入输出格式,就可以过这个题了。

本文探讨了字典树在解决数字串重复问题的应用,通过排序和子串路径判断,有效检测输入串中是否存在重复前缀,提供了解决方案及优化策略。
763

被折叠的 条评论
为什么被折叠?



