Trie树 应用 Phone List

Phone List

时间限制: 5000 ms  |  内存限制: 65536 KB
描述

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another.

 

Let’s say the phone catalogue listed these numbers:

 

  • Emergency 911
  • Alice 97 625 999
  • Bob 91 12 54 26

In this case, it’s not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob’s phone number. So this list would not be consistent.

输入

The first line of input gives a single integer, 1 ≤ t ≤ 40, the number of test cases. Each test case starts with n , the number of phone numbers, on a separate line, 1 ≤ n ≤ 10000.

 

Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

输出

For each test case, output “YES” if the list is consistent, or “NO” otherwise.

样例输入
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
样例输出
NO
YES
     这题是一个标准的Trie树,如果处理好的话用排序也可以过,话说效率 还是挺不错的,但这里要讲的是Tire树做法。字符串处理的算法有很多,Trie树和Trie图(也就是AC自动机)都是很高效的数据结构,后缀数组也 是,但是由于后缀数组较为复杂,实现起来也比较恼火。Trie树是一棵度 m ≥ 2 的树,它的每一层分支不是靠整个关键码的值来确定,而是由关键码的一个分量来确定。关键码可以是英文字母,也可以是数字(这里的数据我们当作字符处理)。 Trie的基本操作有插入,删除,查询,实现起来也是比较容易的。      用动态添加节点北航的OJ能过,但是POJ过不了,听说用静态的,本人暂时不会哈。所以给出的是动态添加的方法。

     针对这一题来分析:

           题 意:给n个串,看是否有一个串是另一个串的前缀。因为数据量相对来讲比较大,如果用两两比较,会TL,所以 O(n^2)显然过不了这题。  字典树却很容易处理,设置节点信息包括flag标志是否到达一个单词尾部,另外设置一个数组记录此结点的儿子结点的数组下标。在插入过程中就可以进行查询。

 

   自己写的Trie动态插入版本

 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX 10

typedef struct TrieNode{
	bool isPhone;
	TrieNode *next[MAX];
	void initialTrie(){
		isPhone = false;
		for(int i = 0 ; i < MAX ; i++){
			next[i] = NULL;
		}
	}
}TrieNode;

bool isPrefixPhone = false;



void addWord(TrieNode *node,char *ch){
	if(node == NULL || *ch == '\0')
		return;
	TrieNode *p = node;
	int i,len;
	for(i = 0 ; i < (len=strlen(ch)) ; i ++){
		if(p->next[ch[i]-'0'] == NULL){
			TrieNode *tmp = (TrieNode*)malloc(sizeof(TrieNode));
			//初始化以temp为顶点节点的子树
			tmp->initialTrie();
			p->next[ch[i]-'0'] = tmp;	
		}else{		
			if(p->next[ch[i]-'0']->isPhone && i <= len - 1){
				isPrefixPhone = true;
				return;
			}
		}
		p = p->next[ch[i]-'0'];
	}
	p->isPhone = true;
	//如果先输入12,再输入1,那么就需要下面的代码进行判断
	for(i = 0 ; i < MAX ; i ++){
		if(p->next[i] != NULL){
			isPrefixPhone = true;
			return;
		}
	}
}


void delTree(TrieNode *root){
	for(int i = 0 ; i < MAX ; i ++){
		if(root->next[i] != NULL){
			delTree(root->next[i]);
		}
		delete root->next[i];
	}
}



int main(){
	int t,n,i;
	char s[11];
	scanf("%d",&t);
	TrieNode *root = (TrieNode*)malloc(sizeof(TrieNode));
	while(t--){	
		root->initialTrie();
		isPrefixPhone = false;
		scanf("%d",&n);
		for(i = 0 ; i < n ; i ++){
			scanf("%s",s);
			if(isPrefixPhone) continue;
			addWord(root,s);
		}
		printf(isPrefixPhone ? "NO\n":"YES\n");
		delTree(root);
	}
	return 0;
}

 

    网上大牛写的静态版

 

 

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXNODE=500000;
    const int BRANCH=10;

    int Tree[MAXNODE][BRANCH],SIZE;
    bool Key[MAXNODE];
    bool Insert(char *str) {
        int Node=0;bool tof=false;
        for (int i=0;str[i];i++){
            int c=str[i]-'0';
            if(Tree[Node][c]==-1){
                Tree[Node][c]=++SIZE;tof=true;
                memset(Tree[SIZE],-1,sizeof(Tree[SIZE]));
            }
            if(Key[Node]) return false;
            Node=Tree[Node][c];
        }
        Key[Node]=true;
        return tof;
    }

    void Trie(){
        memset(Tree[0],-1,sizeof(Tree[0]));
        SIZE=0;
    }

    char str[15];
    int main()
    {
        int t,n;bool tof;
        scanf("%d",&t);
        while(t--){
            memset(Key,false,sizeof(Key));
            Trie();tof=true;
            scanf("%d",&n);
            for(int i=0;i<n;i++){
                scanf("%s",str);
                if(tof){
                    tof=Insert(str);
                }
            }
            if(tof) puts("YES");
            else puts("NO");
        }
    }
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值