(hdu step 5.2.2)统计难题(求一堆单词中以某一单词为前缀的单词的个数)

本文详细介绍了如何使用字典树(Trie)数据结构来解决统计给定单词表中以特定字符串为前缀的单词数量的问题。通过插入单词并查找前缀,实现高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

统计难题

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)
Total Submission(s): 349 Accepted Submission(s): 209
 
Problem Description
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
 
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.
 
Output

            对于每个提问,给出以该字符串为前缀的单词的数量.
 
Sample Input
banana
band
bee
absolute
acm

ba
b
band
abc
 
Sample Output
2
3
1
0
 
Author
Ignatius.L
 
 
Recommend
Ignatius.L


题目分析:

               Trie的基本题。这道题提交的时候使用C++提交,使用G++提交会MLE。而且杭电有时候很搞笑的,这道题

很快就敲出来了,提交以后一直TLE。后来中午再交一次的时候,就正常了,在200ms左右。如果TLE了就多交几次吧。。



代码如下:

/*
 * b.cpp
 *
 *  Created on: 2015年3月8日
 *      Author: Administrator
 */

#include <iostream>
#include <cstdio>
#include <cstring>


using namespace std;

const int MAX = 26;

typedef struct TrieNode{//Trie结点
	int prefix;//到当前节点的前缀数
	struct TrieNode* next[MAX];//当前节点的孩子节点
}Trie;


/**
 * Trie树的插入操作:
 * 将字符串s插入到以root为根的字典树中
 *
 */
void insert(Trie* root,char* s){
	//如果当前的字典树的根为空||要插入的字符串为空
	if(root == NULL || *s == '\0'){
		return ;//则直接返回
	}

	Trie* p = root;

	while(*s != '\0'){//不断地遍历要插入的字符串的每一个字符
		if(p->next[*s - 'a'] == NULL){//如果字典树中还没有该节点,则新建该节点
			//新建结点的初始化操作
			Trie* temp = (Trie*)malloc(sizeof(Trie));
			int i;
			for(i = 0 ; i < MAX ; ++i){
				temp->next[i] = NULL;
			}
			temp->prefix = 1;//新建该节点后的前缀数默认为1

			p->next[*s-'a'] = temp;//用next指向temp
			p = p->next[*s-'a'];//遍历下一个节点
		}else{//如果该节点在字典树中已经存在
			p = p->next[*s - 'a'];//遍历下一个节点
			p->prefix++;//到该节点的前缀数+1
		}

		s++;//遍历该字符串的下一个字符
	}
}


/**
 * 在以root为根字典树中寻找以pre为前缀的单词数有多少个
 */
int count(Trie* root,char* pre){
	Trie* p = root;

	while(*pre != '\0'){//不断地遍历该前缀字符串
		if(p->next[*pre - 'a'] == NULL){//如果某一结点的孩子节点中不包含pre当前遍历的字符
			return 0;//则表明单词中没有一pre为前缀的单词,直接返回0
		}else{//如果当前节点的孩子节点中有pre当前遍历到的字符
			//则继续遍历
			p = p->next[*pre - 'a'];
			pre++;
		}
	}

	return p->prefix;//返回以pre开头的单词数
}


/**
 * 字典树的释放操作
 */
void del(Trie* root){
	int i;
	for(i = 0 ; i < MAX ; ++i){
		if(root->next[i] != NULL){
			del(root->next[i]);
		}
	}

	free(root);
}


int main(){

	char str[11];

	//初始化操作
	Trie* root = (Trie*)malloc(sizeof(Trie));
	int i;
	for(i = 0 ; i < MAX ;++i){
		root->next[i] = NULL;
	}
	root->prefix = 0;


	while(gets(str)){//不断地读入字符串
		if(strcmp(str,"") == 0){//如果当前读入的是空串
			break;//则跳出循环
		}

		insert(root,str);//将当前读到的字符串插入字典树中
	}

	while(gets(str)){
		printf("%d\n",count(root,str));
	}

	del(root);//如果没有这个操作耗时只有100ms左右。如果加上这个操作耗时将达到200ms左右。

	return 0;
}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的东哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值