Trie 树(字典树、前缀树)

Trie 树


Trie树也叫做字典树、前缀树。Trie树是一种树形结构,常用作存储字符串,利用存储字符串相同的公共前缀来减少检索所需要的时间。
Trie树的性质

根节点不包含字符,除根节点外每一个节点都只包含一个字符 从根节点到某一节点,
路径上经过的字符连接起来,为该节点对应的字符串

每个节点的所有子节点包含的字符都不相同

例如:
下列字符串所构建的Trie树

a
abc
abcd 
abd
bcd

Trie 树(字典树、前缀树)_第1张图片
上图标红表示此处有字符串结尾(实际代码中用额外数组来记录以每个字母结点结尾的字符串数量),节点内数字为结点编号。

模板题

维护一个字符串集合,支持两种操作:

1. I x 向集合中插入一个字符串 x;
2. Q x 询问一个字符串在集合中出现了多少次。
共有 N 个操作,输入的字符串总长度不超过 10^5,字符串仅包含小写英文字母。

输入格式
第一行包含整数 N,表示操作数。

接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。

输出格式
对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。

每个结果占一行。

数据范围
1≤N≤2∗10^4
输入样例:
5
I abc
Q abc
Q ab
I ab
Q ab
输出样例:
1
0
1

模板代码:

#include
#include
#include
#include
#include
using namespace std;
const int N=1e5+10;
int p[N][26],cnt[N],t=0;
void insert(char str[]){//构建trie树
    int r=0;
    for(int i=0;str[i];i++){
        if(!p[r][str[i]-'a'])
            p[r][str[i]-'a']=++t;
        r=p[r][str[i]-'a'];
    }
    cnt[r]++;//记录以编号r结点结尾的字符串数量
}
int query(char str[]){//查询与构建Trie树代码相似
    int r=0;
    for(int i=0;str[i];i++){
        if(!p[r][str[i]-'a']) return false;
        r=p[r][str[i]-'a'];
    }
    return cnt[r];
}
int main(){
    int n;
    char op[2],str[N];
    cin>>n;
    while(n--){
        scanf("%s%s",op,str);
        if(op[0]=='I') insert(str);
        else printf("%d\n",query(str));
    }
    return 0;
}

最大异或对

在给定的 N 个整数 A1,A2……AN 中选出两个进行 xor(异或)运算,得到的结果最大是多少?

输入格式
第一行输入一个整数 N。

第二行输入 N 个整数 A1~AN。

输出格式
输出一个整数表示答案。

数据范围
1≤N≤10^5,
0≤Ai<2^31
输入样例:
3
1 2 3
输出样例:
3

分析:异或操作相同为0,不同为1.当求与X异或的最大值时,将X转化为二进制,从高位到低位尽量找与当前X二进制位不同的结点。
代码如下:

#include
#include
#include
#include
using namespace std;
const int N=4e6,M=1e5+10;
int n;
int p[N][2],cnt[N],idx=0;
void set_tree(int x){
    int t=0;
    for(int i=30;~i;i--){
        int c=(x>>i)&1;
        if(!p[t][c]) p[t][c]=++idx;
        t=p[t][c];
    }
    cnt[t]++;
}
int find(int x){
    int t=0,res=0;
    for(int i=30;~i;i--){
        int c=(x>>i)&1;
        if(p[t][!c]){
            res+=1<<i;
            t=p[t][!c];
        } 
        else t=p[t][c];
    }
    return res;
}
int main(){
    int a[M];
    int res=0;
    cin>>n;
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        set_tree(a[i]);
    }
    for(int i=0;i<n;i++) res=max(res,find(a[i]));
    cout<<res<<endl;
    return 0;
}

Trie树比较消耗空间,一般题目内都会对结点数量进行限制

你可能感兴趣的:(字符串,数据结构,c++,算法,字符串,Trie树)