poj_3630 trie树
题目大意
给定一系列电话号码,查看他们之间是否有i,j满足,号码i是号码j的前缀子串。
题目分析
典型的trie树结构。直接使用trie树即可。但是需要注意,若使用指针形式的trie树,则在大数据量下new/delete会很耗时,因此使用静态数组来存储trie树结构。使用静态数组代替指针在oj中常用于节省时间!
实现(c++)
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #define MAX_CHILD_NUM 10 #define MAX_NODE_NUM 1 << 16 struct TrieNode{ int count; int childs[MAX_CHILD_NUM]; TrieNode(){ count = 0; memset(childs, 0, sizeof(childs)); } }; TrieNode gNodes[MAX_NODE_NUM]; //静态数组方式存储 int gCount; bool Insert(int root, char* str){ int node = root; char* p = str; while (*p != '\0'){ int index = *p - '0'; if (gNodes[node].childs[index] == 0){ gNodes[node].childs[index] = gCount++; } node = gNodes[node].childs[index]; if (gNodes[node].count == 2){ //若为某个号码的结尾,则说明出现了前缀子串。 return false; } if (*(p + 1) == '\0'&&gNodes[node].count == 1){ //特殊情况,画图分析很容易看出 return false; } gNodes[node].count = 1; //为1 表示该节点是某个号码内部的点 p++; } if (gNodes[node].count == 2){ //为2说明该点是某个号码结尾的点 return false; } gNodes[node].count = 2; return true; } int main(){ int cas; char number[20]; scanf("%d", &cas); for (int i = 0; i < cas; i++){ memset(gNodes, 0, sizeof(gNodes)); gCount = 2; int n; scanf("%d", &n); getchar(); bool flag = true; for (int k = 0; k < n; k++){ scanf("%s", number); if (flag) flag = Insert(1, number); } if (!flag) printf("NO\n"); else printf("YES\n"); } return 0; }