(hdu step 5.2.3)Phone List(Trie实现:在一堆号码中,判断是否有号码是其他号码的前缀)

题目:

Phone List

Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 239 Accepted Submission(s): 96
 

Problem Description

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:
1. Emergency 911
2. Alice 97 625 999
3. 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.


Input

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.


Output

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


Sample Input

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346


Sample Output

NO
YES

 

Source

2008 “Insigma International Cup” Zhejiang Collegiate Programming Contest - Warm Up(3)


Recommend

lcy

题目分析:

前一篇博客介绍了这道题的非Trie做法。那么这一篇介绍一下这道题的设计初衷:Trie的基本使用——在前缀匹配中的应用。

以下介绍一下Trie的基本知识点(个人理解,请各位批判地接受)。

1、性质

1)根节点不包含任何字符

2)某一结点的所有子节点包含的字符都不相同。

3)从根节点开始到某一结点所经过的路径就是到该节点为止所能形成的单词。

2、基本操作

1)添加:

假设存在字符串str,Trie树的根结点为root。i=0,p=root。

1)取str[i],判断p->next[str[i]-97]是否为空,若为空,则建立结点temp,并将p->next[str[i]-97]指向temp,然后p指向temp;若不为空,则p=p->next[str[i]-97];

2)i++,继续取str[i],循环1)中的操作,直到遇到结束符‘\0‘,此时将当前结点p中的isStr置为true。

void insert(Trie* root,char* s){
	if(root == NULL || s == ‘\0‘){
		return ;
	}

	Trie* p = root;

	while(*s != ‘\0‘){
		if(p->next[*s-‘a‘] == NULL){
			Trie* temp = malloc(sizeof(Trie));

			int i;
			for(i = 0 ; i < MAX ; ++i){
				temp->next[i] = NULL;
			}
			temp->isStr = false;
			p->next[*s-‘a‘] = temp;

			p = p->next[*s-‘a‘];
		}else{
			p = p->next[*s-‘a‘];
		}

		s++;
	}

	p->isStr = true;
}

2)查询:

假设要查找的字符串为str,Trie树的根结点为root,i=0,p=root

1)取str[i],判断判断p->next[str[i]-97]是否为空,若为空,则返回false;若不为空,则p=p->next[str[i]-97],继续取字符。

2)重复1)中的操作直到遇到结束符‘\0‘,若当前结点p不为空并且isStr为true,则返回true,否则返回false。

bool search(Trie* root,char* s){
	Trie* p = root;

	while(p != NULL && *s != ‘\0‘){
		p = p->next[*s-‘a‘];
		s++;
	}

	return (p != NULL && p->isStr);
}

3)删除:

以递归的形式进行删除。

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

	free(root);
}

3、实现的基本思路

1)从根节点开始一次搜索

2)去除关键词的第一个字符,并根据该字符选择相应的子树,然后转到相应的子树中去继续搜索

3)不断地重复2)操作指导完成搜索

4)在某个节点处,如果关键词的所有字符已经被取出。则读出该节点的附加信息。

代码如下:

/*
 * c2.cpp
 *
 *  Created on: 2015年3月7日
 *      Author: Administrator
 */

#include <iostream>
#include <cstdio>

using namespace std;

const int MAX = 10;//每个节点的孩子节点数

bool flag;//用于标记是否存在一个号码是另外一个号码的前缀的情况

typedef struct TrieNode{//字典树Trie结点
	bool isStr;//用于标记到该节点是否形成单词
	struct TrieNode* next[MAX];//每个节点的孩子节点
}Trie;

/**
 * 字典树(前缀树)Trie的插入操作
 * 将字符串s插入根为root的字典树中
 */
void insert(Trie* root,char* s){

	if(root == NULL || s == ‘\0‘){//如果这个字典树为空||需要插入的字符串为空
		return ;//直接返回
	}

	Trie* p = root;

	while(*s != ‘\0‘){//顺序遍历要插入的这个字符串
		if(p->next[*s-‘0‘] == NULL){//如果目前这个孩子节点还不存在
			//则新建该节点
			Trie* temp = (Trie*)malloc(sizeof(Trie));
			int i;
			for(i = 0 ; i < MAX ; ++i){
				temp->next[i] = NULL;
			}
			temp->isStr = false;
			p->next[*s-‘0‘] = temp;//将p中的孩子节点指向新建的这个temp结点

			p = p->next[*s-‘0‘];//更新当前在字典树中查找到的结点
		}else{
			p = p->next[*s-‘0‘];//更新当前在字典树中查找到的结点
		}

		if(p->isStr == true){//如果当前查找到的结点是之前某一个单词的结束结点,则表明存在某一个号码是另外一个号码的前缀的情况
			flag = true;//将flag标记为true.表明存在某一个号码是另外一个号码的前缀的情况
			return ;//已经能得到结果.返回
		}

		//如果能继续执行以下代码,表明到当前结点为止,不存在号码是另外一个号码的前缀的情况.

		s++;//继续遍历下一个节点
	}

	p->isStr = true;//字符串已经插入完毕.将该节点的isStr标记为true,表明在这里可以形成一个号码

	int i;
	for(i = 0 ; i < MAX ; ++i){//遍历该节点的所有子节点
		if(p->next[i] != NULL){//如果该子节点存在.
			flag = true;//说明该号码是另外一个号码的前缀.将flag标记为true
			break;//跳出循环
		}
	}
}

/**
 * 字典树(前缀树)Trie的查找操作
 * 如果以root为根的字典树中存在s字符串.则返回true,
 * 否则返回false
 */
bool search(Trie* root,char* s){
	Trie* p = root;

	while(p != NULL && *s != ‘\0‘){//如果当前遍历到的结点不为NULL&&字符串s还没有遍历完
		//则继续遍历
		p = p->next[*s-‘0‘];
		s++;
	}

	return (p != NULL && p->isStr);//判断结束结点是否存在&&是否在该节点出形成一个号码
}

/**
 * 字典树(前缀树)Trie的删除操作
 *
 */
void del(Trie* root){
	int i;
	for(i = 0 ; i < MAX ; ++i){//遍历该节点的所有孩子节点
		if(root->next[i] != NULL){//如果该孩子节点不为NULL
			del(root->next[i]);//递归删除该孩子节点的孩子节点
		}
	}

	free(root);//释放空间
}

int main(){
	int t;
	scanf("%d",&t);
	char s[11];

	while(t--){
		flag = false;

		//初始化操作
		Trie* root = (Trie*)malloc(sizeof(Trie));
		root->isStr = false;
		int i;
		for(i = 0 ; i < MAX ; ++i){
			root->next[i] = NULL;
		}

		int n;
		scanf("%d",&n);
		for(i = 0 ; i < n ; ++i){
			scanf("%s",s);

			if(flag == false){//如果当前还不存在某一个号码是另外一个号码的前缀的情况
				insert(root,s);
			}
		}

		if(flag == true){
			printf("NO\n");
		}else{
			printf("YES\n");
		}

		del(root);//释放空间。如果在这里不释放空间,会导致内存激增而最后MLE
	}

	return 0;
}
时间: 2024-10-11 19:16:15

(hdu step 5.2.3)Phone List(Trie实现:在一堆号码中,判断是否有号码是其他号码的前缀)的相关文章

(hdu step 5.2.3)Phone List(在一堆号码中,判断是否有号码是其它号码的前缀)

题目: Phone List Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 235 Accepted Submission(s): 92   Problem Description Given a list of phone numbers, determine if it is consistent in the sense that n

(hdu step 4.1.5)find the nth digit(求S串中的第n个位置上是什么数字)

题目: find the nth digit Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 689 Accepted Submission(s): 244   Problem Description 假设:S1 = 1S2 = 12S3 = 123S4 = 1234.........S9 = 123456789S10 = 123456789

(hdu step 1.3.8)Who&#39;s in the Middle(排序)

题目: Who's in the Middle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2938 Accepted Submission(s): 1109   Problem Description FJ is surveying his herd to find the most average cow. He wants to k

(hdu step 1.3.1)FatMouse&#39; Trade(在收入需要一定的付出的情况下求最大收入)

题目: FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5092 Accepted Submission(s): 1530   Problem Description FatMouse prepared M pounds of cat food, ready to trade with the cats gua

HDU 11488 Hyper Prefix Sets (字符串-Trie树)

H Hyper Prefix Sets Prefix goodness of a set string is length of longest common prefix*number of strings in the set. For example the prefix goodness of the set {000,001,0011} is 6.You are given a set of binary strings. Find the maximum prefix goodnes

(hdu step 6.1.2)Eddy&#39;s picture(在只给出二维坐标点的情况下,求让n个点连通的最小费用)

题目: Eddy's picture Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 172 Accepted Submission(s): 126   Problem Description Eddy begins to like painting pictures recently ,he is sure of himself to be

(hdu step 5.1.1)A Bug&#39;s Life((ai,bi)表示ai、bi不在同一堆中,有若干对数据,判断是否有bug)

题目: A Bug's Life Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 723 Accepted Submission(s): 277   Problem Description Background Professor Hopper is researching the sexual behavior of a rare spe

(hdu step 3.2.4)FatMouse&#39;s Speed(在第一关键字升序的情况下,根据第二关键字来求最长下降子序列)

在写题解之前给自己打一下广告哈~..抱歉了,希望大家多多支持我在CSDN的视频课程,地址如下: http://edu.csdn.net/course/detail/209 题目: FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1034 Accepted Submission(s): 526   Proble

HDU 1075 What Are You Talking About Trie题解

翻译火星语,不过火星语也是使用英文单词的,就是把一个单词对应到另外一个单词. 可以使用map, 使用二分,方法很多. 不过最快的应该都是Trie解法了. 把火星语挂在Trie树中,然后在叶子节点增加一个string容器,装英语单词. 查找的时候,找到了出现在Trie中的火星语,就返回string就可以了. #include <stdio.h> #include <string> #include <string.h> using namespace std; const