NYOJ163 Phone list(续)

很明显,二逼青年的作法不是最优的,当然我们肯定是不想做二逼青年撒~OK,这里来一个高富帅版本的。不过要是想看看屌丝的世界,也可以点回去比较比较区别。前一种方法费时608ms,而这里费时176ms。
下面来说说新的方法,其实就是我们熟知的字典树啦。当然,由于我比较懒,所以在网上截了一个图来说明啦~


把图中的字母换成数字就可以了,当然这个题有它自己的特殊性,每一个节点的next其实都是一个数组。
1、字符串中的数字都是0~9。所以next开到10就够了,而且还可以实现随机访问。
2、由于电话号码一般最长是11位,假设极端的条件下,10^5个数据,每个数据都新占一个节点,最多是10^6+个。所以这里node数组的大小去成10^6+5。这其实不是极端情况下的最大值。
3、node[0]为整个字典树的总的根节点。
由于这里可能需要多次的数据检验,所以没必要不停的动态分配内存,用一个足够大的内存就可以了。
参考代码:

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

const int N = 1000005;
const int ARR_SIZE = 10;
struct NODE
{
	bool IsLast;//标记是不是字符串的最后一个字符
	NODE *next[ARR_SIZE];
};
NODE node[N];
const int Size = ARR_SIZE * sizeof(NODE *);
bool Insert(char *str, int &top)
{
	int nLen = strlen(str);
	NODE *p = &node[0];
	for(int i = 0; i < nLen; ++i)
	{
		//如果其根节点是字符串的尾节点,由题知,这里不需要考虑两个号码完全相同的情况
		if(p->IsLast)
			return true;
		if(p->next[str[i] - '0'] == NULL)//以前不存在,加入
		{
			node[top].IsLast = (i == nLen - 1) ? 1 : 0;
			memset(node[top].next, 0, Size);
			p->next[str[i] - '0'] = &node[top];
			++top;
		}
		else if(i == nLen - 1)//当前节点已经存在且是最后的字符了,返回
			return true;
		p = p->next[str[i] - '0'];		
	}
	return false;
}

int main()
{
	int t,n,i;
	char str[13];
	bool flag;
	int top;
	scanf("%d", &t);
	while(t--)
	{
		flag = 0;
		top = 1;
		node[0].IsLast = 0;
		memset(node[0].next, 0, Size);
		scanf("%d", &n);
		for(i = 0; i < n; ++i)
		{
			scanf("%s", str);
			if(!flag)
				flag = Insert(str, top);
		}
		if(flag)
			printf("NO\n");
		else
			printf("YES\n");
	}
	return 0;
}        


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值