字符串哈希与字典树

Posted 175426-hzau-zxjc-con

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串哈希与字典树相关的知识,希望对你有一定的参考价值。

Description

给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串。

Input

输入,第一行一个N
接下来N行每行包含一个字符串

Output

输出不同字符串的个数

Sample Input

5
abc
aaaa
abc
abcc
12345

Sample Output

4
#include <iostream>
#include<algorithm>
#include<string>
using namespace std;
typedef unsigned long long ull;
const ull mod1=1e9+7,mod2=1e9+3,k=131;
struct has
{
    ull x,y;
}a[100001];
ull hash1(string s)
{
    ull len=s.size();
    ull ans=0;
    for(ull i=0;i<len;i++)
    {
        ans=(ans*k+(ull)s[i])%mod1;
    }
    return ans;
}
ull hash2(string s)
{
    ull len=s.size();
    ull ans=0;
    for(ull i=0;i<len;i++)
    {
        ans=(ans*k+(ull)s[i])%mod2;
    }
    return ans;
}
bool cmp(has a,has b)
{
    return a.x>b.x;
}
int main()
{
    int n;
    string s;
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        a[i].x=hash1(s);
        a[i].y=hash2(s);
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y)
            ans++;
    }
    cout<<ans<<endl;
    return 0;
}

Description

HHM在阅读一篇文章,他想找出来一个单词的频率,也就是这个单词在文章中出现了几次。聪明的你赶快帮帮他

Input

输入包含多组数据。

输入文件的第一行有一个整数,代表数据组数。接下来是这些数据,以如下格式给出:

第一行是单词W,一个由{‘A‘,‘B‘,‘C‘,...,‘Z‘}中字母组成的字符串,保证1<=|W|<=10000(|W|代表字符串W的长度)

第二行是文章T,一个由{‘A‘,‘B‘,‘C‘,...,‘Z‘}中字母组成的字符串,保证|W|<=|T|<=1000000。

Output

对每组数据输出一行一个整数,即W在T中出现的次数。

Sample Input

3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN

Sample Output

1
3
0

HINT

字符串哈希思路

#include<stdio.h>
#include<string.h>
#include<iostream>
#define ll unsigned long long
using namespace std;
ll hash[1000005],x,cf[1000005];
char a[1000005];
void read(ll &s,int &l)
{

    s=l=0;
    char c=getchar();
    while(!(c>=A&&c<=Z))
    {
        c=getchar();
    }
    while(c>=A&&c<=Z)
    {
        l++;
        s*=27;
        s+=c-A+1;
        c=getchar();
    }
}
ll ask(int i,int j)
{
    return hash[j]-hash[i-1]*cf[j-i+1];

}
void work()
{
    int i,l1,l2,s=0;
    read(x,l1);
    scanf("%s",a+1);
    l2=strlen(a+1);
    hash[1]=a[1]-A+1;
    for(i=2;i<=l2;i++)
    {
        hash[i]=hash[i-1]*27+a[i]-A+1;
    }
    for(i=1;i<=l2-l1+1;i++)
    {
        if(ask(i,i+l1-1)==x)
            {
                s++;
            }
    }
    printf("%d
",s);
}
int main()
{
    int t,i;
    for(cf[0]=1,i=1;i<=1000000;i++)
    {
        cf[i]=cf[i-1]*27;
    }
    scanf("%d",&t);
    while(t--)
    {
        work();
    }
    return 0;
}

Description

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

Input

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

Output

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

Sample Input

banana
band
bee
absolute
acm
#
ba
b
band
abc

Sample Output

2
3
1
0
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
struct node{
    int num;
    node* next[26];
    node()
    {
        num=0;
        memset(next,0,sizeof(next));
    }
};
node* root=new node();
node* rt;
int id,len;
void bulit(string str)
{
    rt=root;
    len=str.size();
    for(int i=0;i<len;i++)
    {
        id=str[i]-a;
        if(rt->next[id]==NULL)
            rt->next[id]=new node();
        rt=rt->next[id];
        rt->num++;
    }
}
int query(string str)
{
    rt=root;
    len=str.size();
    for(int i=0;i<len;i++)
    {
        id=str[i]-a;
        if(rt->next[id]==NULL)
            return 0;
        rt=rt->next[id];
    }
    return rt->num;
}
int main()
{
    char str[100];
    while(gets(str))
    {
        if(str[0]==#)break;
        build(str);
    }
    while(gets(str))
    {
        printf("%d
",querry(str));
    }
    return 0;
}

Description

HHM和SY做游戏,SY给HHM一个集合,集合包含了N个整数,随后SY向HHM发起M次询问,每次询问包含一个整数S,之后HHM需要在集合中
找到一个正整数K,使得K与S的异或结果最大。HHM向你请求帮助

Input

输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。

Output

对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。

Sample Input

2
3 2
3 4 5
1
5
4 1
4 6 5 6
3

Sample Output

Case #1:
4
3
Case #2:
4
#include <bits/stdc++.h>

using namespace std;

const int maxn=1e5+10;

typedef long long LL;

int ch[32 * maxn][2];
LL value[32 * maxn];
int node_cnt;
inline void init()
{

    node_cnt = 1;

    memset(ch[0],0,sizeof(ch));

}

inline void Insert(LL x)
{
    int cur = 0;

    for(int i = 32;i >= 0;--i)
    {

        int idx = (x >> i) & 1;

        if(!ch[cur][idx])
        {

            memset(ch[node_cnt],0,sizeof(ch[node_cnt]));

            ch[cur][idx] = node_cnt;

            value[node_cnt++] = 0;

        }

            cur = ch[cur][idx];

    }

    value[cur] = x;

}

inline LL Query(LL x)
{
    int cur = 0;

    for(int i = 32;i >= 0;--i)
    {

        int idx = (x >> i) & 1;
        if(ch[cur][idx ^ 1]) cur = ch[cur][idx ^ 1];
        else cur = ch[cur][idx];

    }

    return value[cur];
}

int main()
{

    int t;

    cin>>t;

    int d=1;

    while(t--)

    {

        int n,m;

        scanf("%d%d",&n,&m);

        int i;

        init();

        for(i=1;i<=n;i++)

        {

            LL x;

            scanf("%lld",&x);

            Insert(x);

        }

        printf("Case #%d:
",d);

        for(i=1;i<=m;i++)

        {

            LL x;

            scanf("%lld",&x);

            printf("%lld
",Query(x));

        }

        d++;
    }
    return 0;
}

 




















以上是关于字符串哈希与字典树的主要内容,如果未能解决你的问题,请参考以下文章

手搓模版系列001-数值哈希/字符串哈希/字典树

数据结构——trie树(字典树)

字典树(前缀树)--Trie

字典树

字典树详解

字典树详解