【每日一练】

一、HDU - 1247 Hat’s Words(字典树)

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

解题思路:模板题目

#include <bits/stdc++.h>
using namespace std;
//#define pb push_back
int tot;
int tre[50005][26];
bool vis[50005];
vector<string>v,ans;
int myInsert(string str,int rt)///插入单词
{
    for(int j=0; j<str.size(); j++)///遍历单词string
    {
        int x=str[j]-'a';
        if(tre[rt][x]==0)///新节点
            tre[rt][x]=++tot;///节点编号
        rt=tre[rt][x];///下一个节点
    }
    vis[rt]=true;///单词末尾标记
}
bool myfinds(string str,int rt)///查询
{
    for(int i=0; i<str.size(); i++)
    {
        int x=str[i]-'a';
        if(tre[rt][x]==0)return false;
        rt=tre[rt][x];
    }
    return vis[rt];
}
int main()
{
    tot=0;
    int num=++tot;
    memset(vis,false,sizeof(vis));
    memset(tre[num],0,sizeof(tre[num]));
    string a;
    v.clear();
    ans.clear();
//    while(cin>>a)///建树
//        insert(a,num),v.pb(a);
    while(cin>>a){
        if(a == "#")
        {
            break;
        }
        ///建树
        myInsert(a,num);
        v.push_back(a);
    }
    for(int i=0; i<v.size(); i++)
    {
        for(int j=0; j<v[i].size(); j++)
        {
            string tma=v[i].substr(0,j+1);
            string tmb=v[i].substr(j+1);
            if(myfinds(tma,num)&&myfinds(tmb,num))
            {
                ///一旦当前单词确定是ans,则可以不用再遍历这个单词剩余的组合
                ans.push_back(v[i]);
                break;
            }
        }
    }
    sort(ans.begin(),ans.end());
    for(int i=0; i<ans.size(); i++) cout<<ans[i]<<"\n";
}

二、HDU - 1251 统计难题

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

Input

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

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

Output

对于每个提问,给出以该字符串为前缀的单词的数量.

Sample Input

banana band bee absolute acm ba b band abc

Sample Output

2 3 1 0

解题思路:Map直接干 也可以直接用字典树模板

#include <bits/stdc++.h>
using namespace std;
int main(){
    char str[10];
    map<string, int> m;
    while(gets(str)){
        int len = strlen(str);
        if ( !len )  break;     //输入了一个空行
        for(int i = len; i>0; i--){
            str[i]='\0';        //从后往前删除这个字符串的字符,得到前缀
            m[str]++;           //统计前缀的数量
        }
    }
    while( gets(str) )  cout << m[str] << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
int trie[1000010][26];       //数组定义字典树,存储下一个字符的位置
int num[1000010]={0};     //以某一字符串为前缀的单词的数量
int pos = 1;               //当前新分配的存储位置
void Insert(char str[]){      //在字典树中插入某个单词
    int p = 0;
    for(int i=0;str[i];i++){
        int n = str[i]-'a';
        if(trie[p][n]==0)    //如果对应字符还没有值
            trie[p][n] = pos++;
        p = trie[p][n];
        num[p]++;
    }
}
int Find(char str[]){    //返回以某个字符串为前缀的单词的数量
    int p = 0;
    for(int i=0;str[i];i++){
        int n = str[i]-'a';
        if(trie[p][n]==0)
            return 0;
        p = trie[p][n];
    }
    return num[p];
}

int main(){
    char str[11];
    while(gets(str)){
        if ( !strlen(str) )  break;  //输入了一个空行
        Insert(str);
    }
    while( gets(str))  cout << Find(str) << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
struct Trie{    //字典树定义
    Trie* next[26];
    int num;    //以当前字符串为前缀的单词的数量
    Trie() {   //构造函数
       for(int i=0;i<26;i++) next[i] = NULL;
       num=0;
    }
};
Trie root;
void Insert(char str[]){    //将字符串插入到字典树中
    Trie *p = &root;
    for(int i=0;str[i];i++){    //遍历每一个字符
        if(p->next[str[i]-'a']==NULL)    //如果该字符没有对应的结点
            p->next[str[i]-'a'] = new Trie;    //创建一个
        p = p->next[str[i]-'a'];
        p->num++;
    }
}
int Find(char str[]){    //返回以字符串为前缀的单词的数量
    Trie *p = &root;
    for(int i=0;str[i];i++){    //在字典树找到该单词的结尾位置
        if(p->next[str[i]-'a']==NULL)
            return 0;
        p = p->next[str[i]-'a'];
    }
    return p->num;
}
int main(){
    char str[11];
    while(gets(str)){
        if ( !strlen(str) )  break;  //输入了一个空行
        Insert(str);
    }
    while( gets(str))  cout << Find(str) << endl;
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值