数据结构--Trie--基础

本文介绍了Trie树(字典树)的基本原理,包括其高效的数据结构特点和在统计大量字符串频率以及异或对求最大值问题中的应用实例。展示了如何使用Trie树进行字符串插入和查询操作,以及在实际编程中的代码实现。
摘要由CSDN通过智能技术生成

简介

引入

字典树 / 前缀树

原理

Trie 树是一种多叉树的结构,每个节点保存一个字符,一条路径表示一个字符串。
功能 : 高效的存储insert和查找query字符串集合的数据结构
核心思想 : 空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的
应用场景 : 统计和排序大量的字符串 【注意有比较多的公共前缀这些字符串】

  • 文本词频统计
  • 前缀匹配
  • 字符串检索

模板代码

向集合中插入一个字符串 x

void insert(char str[])
{
    int p = 0; // 指向根节点
    for(int i = 0; str[i]; i ++)
    {
        int u = str[i] - 'a';
        if(!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}

询问一个字符串在集合中出现了多少次

int query(char str[])
{
    int p = 0;
    for(int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if(!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

应用

835. Trie字符串统计

题目

在这里插入图片描述

分析

这里就是trie树地应用

代码

#include<iostream>

using namespace std;

const int N = 1e5 + 10;

int son[N][26], cnt[N], idx;
char op[2], str[N];

void insert(char str[])
{
    int p = 0; // 指向根节点
    for(int i = 0; str[i]; i ++)
    {
        int u = str[i] - 'a';
        if(!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}

int query(char str[])
{
    int p = 0;
    for(int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if(!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

int main()
{
    int n;
    scanf("%d", &n);
    
    while(n -- )
    {
        scanf("%s%s", op, str);
        if(op[0] == 'I') insert(str);
        else printf("%d\n", query(str));
    }
    
    return 0;
}

143. 最大异或对

题目

在这里插入图片描述

分析

异或规则:1^1 = 0 0 ^ 0 = 0 1 ^ 0 = 1;
所以根据规则,如果两个数地二进制表示中,从个位中表示^差距越大地则最后地结果越大。

代码

#include <iostream>

using namespace std;

const int N = 100010, M = 31 * N;

int n;
int a[N];
int son[M][2], idx;

void insert(int x)
{
    int p = 0;
    for(int i = 30; i >= 0; i --)
    {
        int u = x >> i & 1;
        if(!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    
}


int query(int x)
{
    int p = 0, res = 0;
    for(int i = 30; i >= 0; i --)
    {
        int u = x >> i & 1;
        if(son[p][!u]) 
        {
            p = son[p][!u];
            res = res * 2 + !u;
        }
        else 
        {
            p = son[p][u];
            res = res * 2 + u;
        }
    }
    
    return res;
    
}


int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    
    int res = 0;
    
    for(int i = 0; i < n; i ++)
    {
        insert(a[i]);
        
        int t = query(a[i]);
        res = max(res, a[i] ^ t);
    }
    
    printf("%d", res);
    
    return 0;
}

题单

转载来自Trie 树

level1

P2580 于是他错误的点名开始了
PHONELST - Phone List

level2

level3

level4

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wbzuo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值