首页 > 其他 > 详细

数据结构 01trie树【字典树】

时间:2021-05-19 23:49:41      阅读:28      评论:0      收藏:0      [点我收藏+]

trie树

trie树是一种高效存储和查询字符串集合的数据结构

概念:

【算法竞赛进阶指南】:Tire(字典树)是一种用于实现字符串快速检索的多叉树结构。Trie的每个节点都拥有若干个字符指针(是trie的第二维,记录的根节点的所有儿子节点(互为兄弟节点),若在插入或检索时扫描到一个字符c,就沿着当前节点的c字符指针,走向该指针指向的节点。

过程:

0号节点即是根节点,又是空节点。

插入:

  令指针p起初指向根节点,然后依次扫描字符串S中的每个字符c

  1.将字符c映射一下

  2.若当前字符c不存在,则新开辟一个节点(++ idx),令p根节点的儿子节点等于idx【也就是字符c的指针指向idx】

  3.让p=c的指针

查询:

  令指针p起初指向根节点,然后依次扫描字符串S的每个字符c

  1.将字符c映射一下
  2.若p的c字符指向空,则说明S中没有被插入到trie树种,结束检索

  3.若p的c字符指针指向一个已经存在的节点Q,则令p=Q。

  4.当S中的字符扫描完毕时,若当前节点p被标记为一个字符串的末尾,则说明Trie中存在,否则说明S没有插入过Trie

  

Trie字符串统计

题目:

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

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

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

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

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

每个结果占一行。

数据范围
1≤N≤2?104
输入样例:
5
I abc
Q abc
Q ab
I ab
Q ab
输出样例:
1
0
1

  

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
char s[N], op[2];
int tr[N][26], cnt[N], idx;

void insert(char s[])
{
    int len = strlen(s), p = 0;
    for (int i = 0; i < len; i ++ )
    {
        int t = s[i] - ‘a‘;
        if (!tr[p][t]) tr[p][t] = ++ idx;
        p = tr[p][t];
    }
    cnt[p] ++;
}

int query(char s[])
{
    int len = strlen(s), p = 0;
    for (int i = 0; i < len; i ++ )
    {
        int t = s[i] - ‘a‘;
        if (!tr[p][t]) return 0;
        p = tr[p][t];
    }
    return cnt[p];
}
int main()
{
    cin >> n;
    while (n -- )
    {
        scanf("%s", op);
        scanf("%s", s);
        if (*op == ‘I‘)
        {
            insert(s);
        }
        else 
        {
            printf("%d\n", query(s));
        }
    }
    return 0;
}

  

最大异或对

题目:

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

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

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

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

数据范围
1≤N≤105,
0≤Ai<231
输入样例:
3
1 2 3
输出样例:
3

  

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 3100010;

int n;
int tr[N][2], idx;
//第二维记录的是根节点的儿子的兄弟节点。

void insert(int x)
{
    // cout << x << endl;
    int p = 0;
    for (int i = 31; i >= 0; i --)
    {
        int u = (x >> i & 1);
        if (!tr[p][u]) tr[p][u] = ++ idx;
        p = tr[p][u];
    }
}

int query(int x)
{
    // cout << x << endl;
    int p = 0, ans = 0;
    for (int i = 31; i >= 0; i -- )
    {
        int u = (x >> i & 1) ^ 1;
        if (tr[p][u])
        {
            ans += 1 << i;
            p = tr[p][u];
        }
        else p = tr[p][!u];
    }
    return ans;
}
int main()
{
    cin >> n;
    int res = 0;
    while (n -- )
    {
        int x; scanf("%d", &x);
        insert(x);
        res = max(res, query(x));
    }
    
    cout << res << endl;
    
    return 0;
}

  

牛异或

题目:

农夫约翰在给他的奶牛们喂食时遇到了一个问题。

他共有 N 头奶牛,编号 1~N。

每次喂食前,这 N 头奶牛会按照 1~N 的顺序站成一排。

此外,每头奶牛都被分配了一个可能不唯一的整数。

那么所有被分配的整数就形成了一个长度为 N 的整数序列。

请你在该整数序列中找出一个连续的非空子序列,使得子序列中元素的异或和能够最大。

如果存在多个这样的序列,那么选择序列末端整数对应的奶牛编号更小的那个序列。

如果仍然存在多个可选的序列,那么选择长度最短的那个序列。

输入格式
第一行包含整数 N。

第 2~N+1 行,每行包含一个整数,其中第 i 行的整数表示编号为 i?1 的牛被分配的整数值。

输出格式
输出三个整数,分别表示最大的异或和,所选序列首端整数对应的奶牛编号,所选序列末端整数对应的奶牛编号。

数据范围
1≤N≤105,
分配给奶牛的整数的范围是 [0,221?1]。

输入样例:
5
1
0
5
4
2
输出样例:
6 4 5

  

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
int s[N];
int tr[N * 21][2], id[N * 21], idx;

void insert(int x, int k)
{
    int p  = 0;
    for (int i = 21; i >= 0; i -- )
    {
        int u = x >> i & 1;
        if (!tr[p][u]) tr[p][u] = ++ idx;
        p = tr[p][u];
    }
    id[p] = k;
}

int query(int x)
{
    int p = 0;
    for (int i = 21; i >= 0; i -- )
    {
        int u = x >> i & 1;
        if (tr[p][!u]) p = tr[p][!u];
        else p = tr[p][u];
    }
    return id[p];
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n ;i ++ )
    {
        scanf("%d", &s[i]);
        s[i] ^= s[i - 1];
    }
    
    int ans = -1, l = 1, r = 1;
    for (int i = 1; i <= n; i ++ )
    {
        // insert(s[i], i);
        int k = query(s[i]);
        int res = s[i] ^ s[k];
        if (ans < res) {
            ans = res;
            l = k + 1;//如果存在s[L1 ~ R] == s[L2 ~ R],且L1<L2,在insert的时候会被覆盖掉的,所以不用考虑第三个情况,会自动保留最短
            r = i;
        }
        insert(s[i], i);
    }
    
    cout << ans << ‘ ‘ << l << ‘ ‘ << r << endl;
    
    return 0;
}

  

 

数据结构 01trie树【字典树】

原文:https://www.cnblogs.com/Iamcookieandyou/p/14787413.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!