POJ 3630 Phone List

题目大意:

给出几组电话号码,在某一组号码中,如果存在某一号码为其他号码的前缀,则输出NO,否则输出YES。

解题思路:

方法一:对每组中的电话号码进行排序,然后再从最短的电话开始与后面的电话号码进行比较,判断当前的电话号码是否是其他某些号码的前缀,直到该组结尾。当问题的规模较大时,这种方法的时间复杂度相对较高,然而空间复杂度则较低。

方法二:采用字典树实现对每组号码的存储,再逐一对组中的号码进行判断。这种方法空间复杂度较高,但是时间复杂度则很低。

另外如果每次插入号码时都new一个新的字典树结点,程序提交的结果是TLE。因此建立静态结点缓存,每次从缓存中取结点,插入字典树中。

具体实现代码如下:

#include <cstdio>

struct Trie
{
	int count;
	struct Trie *branch[10];
}Memory[10000]; //建立10000个静态结点

int num = 0;

Trie *TrieNode()
{
	Trie *p = &Memory[num++];
	p->count = 0;
	for(int k = 0; k < 10; k++)
	{
		p->branch[k] = NULL;
	}
	return p;
}

//将字符串number插入根为root的字典树
void MakeTrie(Trie *&root, char *number)
{
	int i = 0;
	if(root == NULL)
	{
		root = TrieNode();
	}
	Trie *p = root;
	while(number[i])
	{
		if(!p->branch[number[i] - '0'])
		{
			p->branch[number[i] - '0'] = TrieNode();

		}
		p = p->branch[number[i] - '0'];
		p->count++;
		i++;
	}
}

//判断字符串number是否为其他某字符串的前缀
//如果是返回true,否则返回false
bool IsPrefix(Trie *root, char *number)
{
	int i = 0;
	if(root == NULL)
	{
		return true;
	}
        Trie *p = root;
	while(number[i])
	{
                p = p->branch[number[i] - '0'];
		if(p->count == 1)
			return false;
		i++;
        }

	return true;
}

int main()
{
	bool flag = true;
	int j, n, t;
	Trie *root = NULL;
	char numbers[10000][11];
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d", &n);
		root = NULL;
		for(j = 0; j < n; j++)
		{
			scanf("%s", numbers[j]);
			MakeTrie(root, numbers[j]);
		}

		for(j = 0; j < n; j++)
		{
			if(IsPrefix(root, numbers[j]))
			{
				flag = false;
				break;
			}
		}
		if(flag)
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
		flag = true;
		num = 0;
	}
	return 0;
}



你可能感兴趣的:(list,null,存储,branch,电话,Numbers)