动物统计加强版
时间限制:3000 ms | 内存限制:150000 KB
难度:4
- 描述
- 在美丽大兴安岭原始森林中存在数量繁多的物种,在勘察员带来的各种动物资料中有未统计数量的原始动物的名单。科学家想判断这片森林中哪种动物的数量最多,但是由于数据太过庞大,科学家终于忍受不了,想请聪明如你的ACMer来帮忙。
- 输入
- 第一行输入动物名字的数量N(1<= N <= 4000000),接下来的N行输入N个字符串表示动物的名字(字符串的长度不超过10,字符串全为小写字母,并且只有一组测试数据)。
- 输出
- 输出这些动物中最多的动物的名字与数量,并用空格隔开(数据保证最多的动物不会出现两种以上)。
- 样例输入
-
10 boar pig sheep gazelle sheep sheep alpaca alpaca marmot mole
- 样例输出
-
sheep 3
字典树的应用
字典树:是一种用于快速检索的多叉树结构。字典树把要查找的关键词看作一个字符序列,并根据构成关键词字符的先后顺序构造用于检索的树结构;一棵m度的字典树树或者为空,或者由m棵m度的Trie树构成。
特点:
利用串的公共前缀->节约内存
根结点不包含任何字母
其余结点仅包含一个字母(非元素)
每个结点的子节点包含字母不同
字典树的查找(最主要的操作)
(1)在trie树上进行检索总是始于根结点。
(2)取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索。
(3)在某个结点处,关相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
(4) ...
键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
Trie的数据结构定义
struct dictree
{
dictree *child[26];
int n; //根据需要变化
};
dictree *root;
特点:数据量大
主要任务:查找单词
解决方法:字典树
字典树结构(除指针):单词信息(英文)
HDOJ-1075 What Are You Talking About
HDOJ-1251 统计难题
HDOJ-1298 T9
HDOJ-1800 Flying to the Mars
ZOJ-1109 Language of FatMouse
第一步:1.建立字典树,
第一次思想(错误):
从第一层向下统计,每次都找到每层次数最多的(这里错误!!)
如测试数据:
5
abc
ade
afr
bb
bb
错误代码:
#include<iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; typedef struct dictree { dictree * child[26]; int cnt; }dictree; void find(dictree * root) { int i,j; int flag = 1; for(i=0;i<26;i++) if(root->child[i]) flag = 0; if(flag){ printf(" %d\n",root->cnt); return; } dictree *p; dictree *q; q = root; int index; int max = 0; for(i=0;i<26;i++)//寻找该层次数最大的然后向下查找,!!!这里错误 r如: abc acd aef bb bb 则先从a向下找了,错误!!!! { p=q->child[i]; if(p) { if(max<p->cnt) { max=p->cnt; index = i; } } } p = q->child[index]; if(p) { printf("%c",index+'a'); find(p); } } void insert(dictree * &root,char s[])//建立字典树 { int j,i; dictree *p; dictree *q; q = root; for(i=0;i<strlen(s);i++) { if(q->child[s[i]-'a']) { q = q->child[s[i]-'a']; q->cnt++; } else { p = (dictree * )malloc(sizeof(dictree));//分配p p->cnt = 1; for(j=0;j<26;j++) p->child[j] = NULL; q->child[s[i]-'a'] = p; q = p; } } } int main() { int i; dictree * root; root=(dictree *)malloc(sizeof(dictree)); for(i=0;i<26;i++) root->child[i] = NULL; int n; char s[11]; scanf("%d",&n); while(n--) { scanf("%s",s); insert(root,s); } find(root); return 0; }
第二次:
统计每个单词最后一个字母的出现次数,找最多的,但是找的过程中错误
建树过程中只统计最后一个单词出现次数,不能每个字母都统计次数
如:
5
abcde
abcde
abcde
ab
ab
此时b是5词,但ab不是最多的,所以会出错。。。!!!!
#include<iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; typedef struct dictree { dictree * child[26]; int cnt; }dictree; char str[12]; int num; void insert(dictree * &root,char s[]) { int j,i; dictree *p; dictree *q; q = root; for(i=0;i<strlen(s);i++) { if(q->child[s[i]-'a']) { q = q->child[s[i]-'a']; q->cnt++;//这里错误,应该放到外面++ } else { p = (dictree * )malloc(sizeof(dictree));//分配p p->cnt = 1; for(j=0;j<26;j++) p->child[j] = NULL; q->child[s[i]-'a'] = p; q = p; } } if(q->cnt>num) {//单词结束后,看最后一个字母出现次数 num = q->cnt; strcpy(str,s); } } int main() { int i; dictree * root; root=(dictree *)malloc(sizeof(dictree)); for(i=0;i<26;i++) root->child[i] = NULL; int n; char s[12]; scanf("%d",&n); num=0; while(n--) { scanf("%s",s); // puts(s); insert(root,s); } printf("%s %d\n",str,num); return 0; }
最后AC代码:
将前面的都改进
#include<iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; typedef struct dictree { dictree * child[26]; int cnt; }dictree; char str[11]; int num; void insert(dictree * &root,char s[]) { int j,i; dictree *p; dictree *q; q = root; for(i=0;i<strlen(s);i++) { if(q->child[s[i]-'a']) { q = q->child[s[i]-'a']; } else { p = (dictree * )malloc(sizeof(dictree));//分配p p->cnt = 0; for(j=0;j<26;j++) p->child[j] = NULL; q->child[s[i]-'a'] = p; q = p; } } q->cnt++;//这里放到外面,只统计最后一个字母出现次数 if(q->cnt>num) { num = q->cnt; strcpy(str,s); } } int main() { int i; dictree * root; root=(dictree *)malloc(sizeof(dictree)); for(i=0;i<26;i++) root->child[i] = NULL; int n; char s[11]; scanf("%d",&n); while(n--) { scanf("%s",s); insert(root,s); } printf("%s %d\n",str,num); return 0; }