hdu 1247 Hat’s Words(字典树)

 

Hat’s Words

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12577    Accepted Submission(s): 4481


Problem Description
A hat’s word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary.
You are to find all the hat’s words in a dictionary.
 

Input
Standard input consists of a number of lowercase words, one per line, in alphabetical order. There will be no more than 50,000 words.
Only one case.
 

Output
Your output should contain all the hat’s words, one per line, in alphabetical order.
 

Sample Input
       
       
       
       
a ahat hat hatword hziee word
 

Sample Output
       
       
       
       
ahat hatword

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1247

字典树讲解链接:

http://www.cnblogs.com/tanky_woo/archive/2010/09/24/1833717.html


【题意】

            输入多个字符串,每个字符串占一行,共一组测试数据,输入完字符串以“CTRL+Z”结束输入。判断输入字符串中是否存在两个字符串组合成一个字符串,即这3个字符串都是刚才输入的字符串,保证绝对存在这样的字符串。


【分析】

           通过对输入的字符串进行创建或添加到树的结点上,构成字典树。运用字符       串函数strncpy(a,x,y)(对a数组从坐标x开始,包括坐标x后的y个字符进行复制)       进行拆分,然后再用字典树查找,看是否存在对应的字符串。此题是完全匹配,      拆分后的字符串不能是字典树种的某个字符串的一部分,必须是整个,即最后要       到达叶结点。


【代码】

#include <cstdio>
#include <cstring>
#include <malloc.h>
#include <iostream>
using namespace std;
#define MAXN 26
char str[50017][117];
typedef struct Trie
{
  	int v;//根据需要变化
  	Trie *next[MAXN];
  //next是表示每层有多少种类的数,如果只是小写字母,则26即可,
  //若改为大小写字母,则是52,若再加上数字,则是62了
}Trie;
Trie *root;

// 函数功能:将输入的字符串保存到字典树里
void createTrie(char *str)
{
  	int len = strlen(str);
  	Trie *p = root, *q;
  	for(int i = 0; i < len; i++)
  	{
   	 	int id = str[i]-'a';    // 将字符型转化为整型,可以不转换,只需把定义的结构体int改为char
   	 	if(p->next[id] == NULL) // 如果没有这个字符的结点
   	 	{
            q = (Trie *)malloc(sizeof(Trie));   // 新建一个结点
            q->v = 1;   //初始v==1,不重要,只要和叶结点一样就行,叶结点表示一个结束条件,所以要不同于其他,其他无要求
            for(int j = 0; j < MAXN; j++)
                q->next[j] = NULL;
            p->next[id] = q;
            p = p->next[id];    // 链表连接结点
    	}
    	else
    	{
     		 p = p->next[id];       // 如果此层有这个字符,就用这个结点执行下一层
    	}
  	}
    p->v = -1;  //若为结尾,则将v改成-1表示,用于判断结束条件,所以要标记一下
}

// 函数功能:查找拆分后的字符串,字典树里是否含有
int findTrie(char *str)
{
    int len = strlen(str);
  	Trie *p = root;
  	for(int i = 0; i < len; i++)
  	{
    	int id = str[i]-'a';    // 将字符转化为数字
   		p = p->next[id];        // 指向下一层结点
    	if(p == NULL) //若为空集,表示不存以此为前缀的串
      		return 0;
   //   if(p->v == -1)   //字符集中已有串是此串的前缀
   //	   return -1;
  	}
  //return -1;   //此串是字符集中某串的前缀
  		if(p->v == -1)  // 说明是完全匹配,即含有拆分后的字符串,不是拆分后的字符串是树里的字符串的一部分
   			 return -1;
  		else
   			 return 0;
}
int main()
{
    root = (Trie *)malloc(sizeof(Trie));    // 开辟空间
  	for(int i = 0; i < MAXN; i++)
   		root->next[i] = NULL;       // 置0
  	int cont = 0;
  	while(scanf("%s",str[cont])!=EOF)   // 一直输入,就算是换行也不结束,只有一组测试
 	{
  	  	createTrie(str[cont]);      // 建立树
 	   	cont++;                     // 记录有多少个字符串
 	}
    char a[117], b[117];
  	for(int i = 0; i < cont; i++)   // 拆分每一个字符串,看是否是其他两个字符串的组合
  	{
        int len = strlen(str[i]);   // 求字符串的长度
    	for(int j = 1; j < len; j++)    // 进行一点一点的拆分成两个字符串
    	{
            memset(a,'\0',sizeof(a));
            memset(b,'\0',sizeof(b));
            strncpy(a,str[i],j);            // 将字符串分隔,分成两个字符串,循环次数很大
      		strncpy(b,str[i]+j,len-j);
      		if(findTrie(a)==-1 && findTrie(b)==-1)  // 如果找到拆分后的两个字符串都在树里,即等于-1,输出
            {
       			 printf("%s\n",str[i]);
       			 break;
      		}
   		 }
  	}
    return 0;
}


路过的大神如果发现BUG,一定要留言。


你可能感兴趣的:(hdu 1247 Hat’s Words(字典树))