字典树

C - 统计难题

Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

Input输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.
Output对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana
band
bee
absolute
acm

ba
b
band
abc
Sample Output
2
3
1
0

字典树的应用主要用于:1、给出m个单词进行n次查找判断字典里是否有该单词。。
2、给出m个单词要求查找字典中相同某前缀的单词个数
#include <iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include <stdio.h>
using namespace std;
int tree[400000][26] = {0} ;//字典树第一个括号里表示根节点,第二个括号表示字母在字母表里的索引
int color[400000] = {0}; // 可标一个单词的末节点也可以记录节点经过的次数
int k = 0 ;//给节点编号
void winsert(string a)//单词插入
{
    int p = 0 ;//根节点

    for(int i = 0 ; i < a.length() ; i++)
    {
        int c = a[i] - '0' ; // 单词索引
        if(!tree[p][c]) // 判断下一节点是否存在,存在就不用再标号,不存在就编号
            tree[p][c] = ++k ;
        p = tree[p][c] ;//将根节点移向下一节点
        color[p]++ ;//记录节点经过的次数
    }


}

bool wsearch(string a)//查找前缀
{
    int p = 0 ;//根节点
    for(int i = 0 ; i < a.length() ; i++)
    {
        int c = a[i] - '0';
        if(!tree[p][c]) return false ;//判断单词字符是否存在
        p = tree[p][c];//根节点移向下一节点
    }
    cout << color[p] << endl ;//输出所以单词具有该前缀的数目
    return true ;
}




int main()
{
     char a[11] ;
     while(gets(a) , strcmp(a , "") != 0)
     {
         winsert(a);//建树
     }
     while(~scanf("%s" , &a))
     {
         if(wsearch(a) == false)//查找
            cout << 0 << endl ;
     }



     return 0;
}

B - Hat’s Words

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.

InputStandard 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.
OutputYour 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

开始题目意思一直理解错误,一开还以为是找由字典里两个单词组在一起其中一个必须是“hat”。。
后来通过网上ac代码测试发现是查找:字典里的某一单词由字典里其他任意两个单词组成即可
一开始我想讲了两个单词加起来(可以试试)。但还是用了分割成两个单词一一查找。。



#include <iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
int tree[400000][26] = {0} ;
int color[400000] = {0};
int k = 0 ;
void winsert(string a)//建树
{
    int p = 0 ;

    for(int i = 0 ; i < a.length() ; i++)
    {
        int c = a[i] - '0' ;
        if(!tree[p][c])
            tree[p][c] = ++k ;
        p = tree[p][c] ;
    }
    color[p] = 1 ;//标记该编号为单词的末节点


}

bool wsearch(string a)//查找单词
{
    int p = 0 ;
    for(int i = 0 ; i < a.length() ; i++)
    {
        int c = a[i] - '0';
        if(!tree[p][c]) return false ;
        p = tree[p][c];
    }
    return color[p] == 1 ; // 判断该节点是否是单词的末节点
}




int main()
{
    string a, b[50000];
    int k = 0 ;
    while(cin >> a)
    {
        winsert(a) ;
        b[k++] = a ;//记录所有插入单词
    }
    for(int i = 0 ; i < k ; i++)
    {
        int len = b[i].length();
        for(int j = 0 ; j < len ; j++)
        {
            string c(b[i] , 0 , j+1) , d(b[i] , j+1 , len - j - 1) ;//将单词任意分割成两部分
            if(wsearch(c) && wsearch(d))//查找两单词
            {
                cout << b[i] <<endl ;//输出符合条件单词
                break ;//避免重复输出该单词            
        }
} } return 0; }

学长的码 没有去把一个单词拆分分别查找两个单词。。而是将一个单词嵌套查找两个单词。。

 
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
char s[400005][26];
int vis[400005],tree[400005][26];
int n=0,num=0,root,id,len;
void insert()
{
    len=strlen(s[n]);
    root=0;
    for(int i=0;i<len;i++)
    {
        id=s[n][i]-'a';
        if(!tree[root][id])
            tree[root][id]=++num;//注意是++num
        root=tree[root][id];
    }
    vis[root]=1;//每个单词结束标记一下
}
int search(char *ss)
{
    len=strlen(ss);
    root=0;
    for(int i=0;i<len;i++)
    {
        id=ss[i]-'a';
        if(tree[root][id])
            root=tree[root][id];
        if(vis[root]==1)
        {
            int root2=0;//根节点继续从0开始
            for(int j=i+1;j<len;j++)
            {
                int id2=ss[j]-'a';
                if(!tree[root2][id2])
                    break;
                root2=tree[root2][id2];
                if(vis[root2]==1&&j==len-1) //注意判断该单词的长度是否也是这两个单词的长度
                    return 1;
            }

        }

    }
    return 0;
}
int main()
{
    while(~scanf("%s",&s[++n]))
    {
        insert();
    }
    for(int i=1;i<=n;i++)
    {
        if(search(s[i]))
           printf("%s
",s[i]);
    }
    return 0;
}




原文地址:https://www.cnblogs.com/nonames/p/11210063.html