杭电OJ 1251 、1671(字典树)

杭电OJ 1251

题目传送门:

1251  统计难题:http://acm.hdu.edu.cn/showproblem.php?pid=1251

1671,Phone List: http://acm.hdu.edu.cn/showproblem.php?pid=1671

用标准的Trie树即可解决。

字典树单词查找树Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。 具体参见我之前的 csdn blog 字典树。

解决代码如下(G++编译):

1251:

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

#define max 26 //此函数只考虑26个英文字母的情况

typedef struct Node
{
	int v;//v可以表示一个字典树到此有多少相同前缀的数目
	struct Node *next[max];
	//是表示每层有多少种类的数,如果只是小写字母,则26即可,若改为大小写字母,则是52
	Node()// 构造函数
	{
		v = 0;
		memset(next, 0, sizeof(next));
	}
}Trie;

void insert(Trie * root, char *str)//trie树插入结点
{
	if(root ==NULL || str == NULL)
		return ;
	int i;
	Trie *t = root;
	char *p = str;
	for(i=0; str[i] != '\0'; i++)
	{
		if(t->next[*p - 'a'] == NULL)
			t->next[*p - 'a'] = new Trie();
		t = t->next[*p - 'a'];
		t->v++;
		++p;
	}
}

void search(Trie *root, char *str)//查找串是否在该trie树中
{
	if(root ==NULL || str == NULL)
		return ;
	int i;
	Trie *t = root;
	char *p = str;
	for(i=0; str[i] != '\0'; i++)
	{
		if(t->next[*p - 'a'] != NULL)
		{
			t=t->next[*p - 'a'];
		}
		else
			break;
		++p;
	}
	if(*p != '\0')
		printf("0\n");
	else
	{
		printf("%d\n", t->v);
	}
}
int main()
{
	Trie *root = new Trie();
	//freopen("input.txt","r",stdin);
	char str[32];
	while(gets(str) && str[0] != '\0')//gets能输入空格,而scanf不行.str[0]判断是否到换行
		insert(root, str);
	while(scanf("%s",str) != EOF)
		search(root, str);
	return 0;
}

1671:

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

#define max 10

typedef struct Node
{
	bool flag;// 表示某个号码是否出现过
	struct Node *next[max];// 每一层出现的号码可能种类
	Node()
	{
		flag = false;
		memset(next,0,sizeof(next));
	}
}Trie;


bool test(Trie *root, char *str)// insert and test 
{
	if( root == NULL || str == NULL)
		return false;
	int i;
	char *p= str;
	Trie *t = root;
	for(i=0; str[i]!='\0'; i++)
	{
		if(t->next[*p-'0'] == NULL)
		{
			t->next[*p-'0'] = new Trie();
		}
		else// 已存在此前缀
		{
			if(t->next[*p-'0']->flag)// 某个号码为此号码的前缀
				return false;
			if(str[i+1] == '\0') // 达到此号码末尾,但是为某个号码的前缀
				return false;
		}
		t = t->next[*p-'0'];
		++p;
	}
	t->flag = true;
	return true;
}

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

int main()
{
	freopen("in.txt", "r", stdin);
	int t,n;
	bool valid;//电话号码列表是否有效
	char str[12];
	Trie *root;
	scanf("%d", &t);
	while(t--)
	{
		root = new Trie();
		valid = true;
		scanf("%d", &n);
		while(n--)
		{
			scanf("%s",str);
			if(valid)
				valid = test(root, str);
		}
		if(valid)
				printf("YES\n");
			else
				printf("NO\n");
		del(root);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值