zoukankan      html  css  js  c++  java
  • 字典树

    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;
    }
    
    
    


  • 相关阅读:
    库函数(汇总)
    IE jQuery ajax 请求缓存问题
    Jarvis OJ-level3
    在64位的linux中运行32位的应用程序
    ROP之linux_x64知识杂记
    2017年网络空间安全技术大赛部分writeup
    Sniper OJ部分writeup
    gdb插件使用方法
    pwntools学习
    linux虚拟机安装值得注意的几点
  • 原文地址:https://www.cnblogs.com/nonames/p/11210063.html
Copyright © 2011-2022 走看看