首页 > 其他分享 >Trie

Trie

时间:2024-10-06 12:11:29浏览次数:7  
标签:idx Trie res int 异或 str

835. Trie字符串统计

模板题:

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

  1. I x 向集合中插入一个字符串 x;
  2. Q x 询问一个字符串在集合中出现了多少次。

共有 N 个操作,所有输入的字符串总长度不超过 10^5,字符串仅包含小写英文字母。

输入格式

第一行包含整数 N,表示操作数。

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

输出格式

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

每个结果占一行。

数据范围

1≤N≤2∗10^4

输入样例:

5
I abc
Q abc
Q ab
I ab
Q ab

输出样例:

1
0
1

个人理解

个人感觉这个Trie是比较简单理解的,直接给上注意点还有图解;

AC代码:

#include <iostream>
using namespace std;
//定义:不超过 10^5;
//符合要求即可;
const int Ma=100010;
//这里的26是a~z(字符串仅包含小写英文字母)
//con[Ma]是记录Trie每个父节点最后一个的子节点(有图解);
//idx是记录c的“下标”;
int Trie[Ma][26],con[Ma],idx;   //这里容易误解的点:26 a~z并不是层级;而是以a~z带头的父节点;
char str[Ma];
//这是构造Trie树;
void insert(char str[]){
    int p=0;
    for(int i=0;str[i];i++){
        int c=str[i]-'a';
        //如果没有记录这个字符,idx开辟一个位置来兜住;
        if(!Trie[p][c]){
            Trie[p][c]=++idx;
        }
        //p来指向下一个;
        p=Trie[p][c];
    }
    //记录最后一个字符的位置的个数; 比如 abcd 记录一次,abcd 再来一次 con[p]=2;
    con[p]++;
}
//查找
int search(char str[]){
    int p=0;
    for(int i=0;str[i];i++){
        int c=str[i]-'a';
        //按顺序找下去,不对直接返回0;
        if(!Trie[p][c]){
            return 0;
        }else{
            //指向下一个;
            p=Trie[p][c];
        }
    }
    //返回结果;
    return con[p];
}
int main(){
    int n;
    cin >> n;
    while(n--){
        char c;
        cin >> c >> str;
        if(c=='I'){
           insert(str);
        }else{
            cout << search(str) << endl;
        }
    }
    return 0;
}

图解:来源--------AC 四谷夕雨

Trie2.PNG

解疑:

Trie[p][c]=++idx; //这是什么?idx干什么用的?    
  • 一维下标:父节点的位置(层级)
    二维下标:当前节点的位置(az->025)
    值:当前节点的id(用idx标识,唯一性)
  • 这里是可以自己图画手推的:手推也可能就会发现用这种方法的话,是会浪费一层里的空间的.......这就自定义想了,在下面我会给出一些例题,是很明显的吧,有优化可以q我
  • 自己手推很重要,本人在没手推之前,总是觉得字符之间会重复什么的.......,手推才意识到idx的强大,idx是即将待操作的结点下标 (看自己的理解吧);
  • 哦对,在这以前要知道怎么构建Trie,要不然够呛,比如abcd 的“路径”是可以保存 abc的只需记录最后一个节点;

相关例题:

AC. 最大异或对:

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

输入格式

第一行输入一个整数 N。

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

输出格式

输出一个整数表示答案。

数据范围

1≤N≤10^5
0≤Ai<2^31

输入样例:

3
1 2 3

输出样例:

3

解析:

  • 异或对:随便两个数进行逻辑异或操作求出两两匹配之间最大的异或值;

  • 逻辑异或操作: 异或(XOR)

    逻辑异或运算,运算规则:相异为一,相同为零。即两个操作数不一样时结果为1,两个操作数相同时结果为0。(这都是二进制的形式比较)

    操作数1 操作数2 结果值
    1 1 0
    1 0 1
    0 1 1
    0 0 0

AC代码(暴力):

#include<iostream>
using namespace std;
int sum[100005],a[100005];
int main(){
    int n,ans=0;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        //前缀和;
        sum[i]=sum[i-1]^a[i];
    }
    //两两比较;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            ans=max(ans,sum[i]^sum[j-1]);
        }
    }
    cout << ans << endl;
    return 0;
}
  • 暴力的做法是:第一个循环时间复杂度O(n),第二个O(N^2),时间复杂度肯定是爆掉的;在下面用Trie优化一下

AC代码(Trie):

#include <iostream>
using namespace std;
//0≤Ai<2^31所以最高位是第30位。
//因为是正数,所以要保证第一位是1
const int Ma=3100010,N=1e5+10;
#define int long long
int e[Ma][2],idx;
int a[N];
//构建Trie;
void insert(int x){
    int p=0;
    for(int i=30;i>=0;i--){
        int u=x >> i & 1;
        if(!e[p][u]) e[p][u]=++idx;
        p=e[p][u];
    }
}
int search(int x){
    int p=0,res=0;
    for(int i=30;i>=0;i--){
        //捋明白位移情况在配合上述的Trie手推就很好理解了
        int u=x >> i & 1;
        //判断同层有没有相反的数,只有1或者0,1取反找0,0取反找1;没有走原路;(建议画图理解)
        if(e[p][!u]){
            p=e[p][!u];
            res=res*2+1;  //这里跟转10进制一样的0*10+n
        }
        else{
            //走原路,不要把取反的值带过来看了......
            p=e[p][u];
            res=res*2+0;
        }
    }
    return res;
}
signed main(){
    int n;
    cin >> n;
    if(n==1){int x;cin >> x;cout << x << endl;return 0;}
    for(int i=0;i<n;i++){
        cin >> a[i];
        insert(a[i]);
    }
    int res=0;
    for(int i=0;i<n;i++){
        res=max(res,search(a[i]));
    }
    cout << res << '\n';
}

总结:手推, 手推 , 还是手推;

再分享一道马蹄的题:

MT2055最大异或和:

给定一串手链,每个珠子被赋予一个价值wi,现要从中截取连续的一段,使得他们的异或和最大(注意,手链还未串上)。

格式

输入格式:

第11行包含一个正整数N;
第22行n个正整数wi​,表示珠子价格。

输出格式:

一个正整数,输出最大异或和。

样例 1

输入:

5
1 2 3 4 5

输出:

7
备注

其中:n≤2000,wi≤100000

早期代码: 前缀和+暴力

#include<iostream>
using namespace std;
int sum[100005],a[100005];
int main(){
    int n,ans=0;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        //前缀和;
        sum[i]=sum[i-1]^a[i];
    }
    //第一个和每一个进行比较;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            ans=max(ans,sum[i]^sum[j-1]);
        }
    }
    cout << ans << endl;
    return 0;
}

后期的优化: 前缀和+Trie

#include <iostream>
using namespace std;
const int Ma=3100010,N=1e5+10;
#define int long long
int e[Ma][2],idx;
int a[N];
void insert(int x){
    int p=0;
    for(int i=30;i>=0;i--){
        int u=x >> i & 1;
        if(!e[p][u]) e[p][u]=++idx;
        p=e[p][u];
    }
}
int search(int x){
    int p=0,res=0;
    for(int i=30;i>=0;i--){
        int u=x >> i & 1;
        if(e[p][!u]){
            p=e[p][!u];
            res=res*2+1;
        }
        else{
            p=e[p][u];
            res=res*2+0;
        }
    }
    return res;
}
signed main(){
    int n;
    cin >> n;
    if(n==1){int x;cin >> x;cout << x << endl;return 0;}
    for(int i=0;i<n;i++){
        cin >> a[i];
        //前缀和
        a[i]^=a[i-1];
        insert(a[i]);
    }
    int res=0;
    for(int i=0;i<n;i++){
        res=max(res,search(a[i]));
    }
    cout << res << '\n';
}
  • 这题是跟上述不同的:这个是实现前缀和的异或相加,在进行异或对操作;

标签:idx,Trie,res,int,异或,str
From: https://www.cnblogs.com/mznq/p/18448971

相关文章

  • DBeaver 连接 mysql 报错:Public Key Retrieval is not allowed
    前言DBeaver连接mysql报错:PublicKeyRetrievalisnotallowed遇到"PublicKeyRetrievalisnotallowed"错误时,通常意味着你正在使用的身份验证方法需要加密连接,但是没有正确地配置客户端或服务器来支持这种加密。解决第一种可以在连接字符串中添加 allowPublicKey......
  • P6105 [Ynoi2010] y-fast trie
    这可能也是一个关于匹配的经典trick。题意给定常数\(C\),你需要维护一个集合\(S\),支持以下操作:1x,加入数\(x\),保证\(x\)之前不存在。2x,删除数\(x\),保证\(x\)之前存在。每次操作后你需要回答$$\max_{i,j\inS,i\not=j}(i+j)\bmodC$$\(Q\le5\times10^5\),强制在......
  • 易优CMS出现:Allowed memory size of 134217728 bytes exhausted (tried to allocate 2
    当你遇到“Allowedmemorysizeof134217728bytesexhausted(triedtoallocate20480bytes)”的错误时,这意味着PHP的内存限制已经耗尽。这种错误通常发生在处理大量数据或执行复杂计算时。为了解决这个问题,可以采取以下几种方法:方法1:修改 php.ini 文件(推荐)找到 php......
  • 易优CMS登录后台报Allowed memory size of 134217728 bytes ex hausted (tried to alo
    当你在登录后台时遇到“Allowedmemorysizeof134217728bytesexhausted(triedtoallocate20480bytes)”的错误提示时,通常是由于PHP的内存限制不足导致的。以下是一些具体的解决步骤:步骤1:检查PHP配置登录宝塔面板登录宝塔面板。在左侧菜单栏选择“软件商店”。......
  • 字典Trie树
    题目描述维护一个字符串集合,支持两种操作:I x 向集合中插入一个字符串 x;Q x 询问一个字符串在集合中出现了多少次。共有 N (1≤N≤2×10^4) 个操作,输入的字符串总长度不超过 10^5,字符串仅包含小写英文字母。输入格式第一行包含整数 N,表示操作数。接下来 N 行,......
  • 为何有时出现:Allowed memory size of 134217728 bytes exhausted (tried to allocate
    出现“Allowedmemorysizeof134217728bytesexhausted(triedtoallocate20480bytes)”这样的错误,意味着PHP脚本运行时消耗的内存超过了PHP配置允许的最大内存限制。这个错误通常是因为PHP脚本处理的数据量过大、内存消耗较高的任务或配置不当引起的。以下是几种解决......
  • BZOJ 4545 DQS 的 trie 题解
    Statement维护一棵树,边权\(\in\{\texttta,\textttb,\textttc\}\),根为\(1\),定义这棵树的子串为从\(1\)走到所有点构成的字符串的所有后缀,需要支持以下操作:问当前树的本质不同子串数给一个点添加一棵子树问一个串在当前树中作为子串的出现次数Solution直接广义SAM+......
  • Anthropic介绍Contextual Retrieval
    人工智能模型要想在特定环境中发挥作用,往往需要获取背景知识。例如,客户支持聊天机器人需要了解具体的业务,而法律分析机器人则需要了解大量的过往案例。开发人员通常使用检索增强生成(RAG)来增强人工智能模型的知识。RAG是一种从知识库中检索相关信息并将其附加到用户提示......
  • MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法
    原文:MySQL8.0PublicKeyRetrievalisnotallowed错误的解决方法参考:ConnectionJava-MySQL:PublicKeyRetrievalisnotallowed在使用MySQL8.0时重启应用后提示com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:PublicKeyRetrievalis......
  • 208. 实现 Trie (前缀树)||Trie字典树模板
    题目:https://leetcode.cn/problems/implement-trie-prefix-tree/description/以前的板子写得太丑陋了,重新写一份><因为是leetcode上的题目,所以是核心代码模式。字典树(Trie)原理:(因为我语言表达能力不行,所以以下内容来源于小美AI机器人><)字典树(Trie)是一种用于高效存储和检索字......