zoukankan      html  css  js  c++  java
  • 字典树及其应用

    浅析字典树

    字典树是一种比较特殊的树,边上有边权(至少我是怎么理解的)。又名“Trie”树。

    大概长这样:

    1hwGtI.png

    (插入了cap,cat,csp,co,code)

    边上是字符集,点上是点的编号,涂成蓝色的代表是单词的结尾。

    字符集可以是a-z0-9true和false等等。

    字典树有效的组织了单词的关系,节省了时间和空间。

    插入单词

    void insert(char *s) {
        int p = 1, len = strlen(s);
        for (int i = 0; i < len; ++i) {
            bool now = s[i] - 'a';
            if (trie[p][now] == 0) trie[p][now] = ++m;
            p = trie[p][now];
        }
        isend[p] = true;
    }
    

    这里trie[x][c]表示从节点xc这条边能达到节点trie[x][c]

    其中,m为节点总数计数,要在插入前赋初始值为 (1)

    这里isend用于标记是否是结尾,有时还需要记录次数。

    查询

    每道题都有他查询的内容,需要因地制宜的写查询函数。

    查询前缀是否出现:

    bool query(char *s) { // 此代码没有编译运行测试过,仅供思路参考,不建议直接复制。
        int p = 1, len = strlen(s);
        for (int i = 0; i < len; ++i) {
            bool now = s[i] - 'a';
            if (trie[p][now] == 0) return false;
            p = trie[p][now];
        }
        return true;
    }
    

    查询出现次数(注意配套修改insert函数):

    int query(char *s) { // 此代码没有编译运行测试过,仅供思路参考,不建议直接复制。
        int p = 1, len = strlen(s);
        for (int i = 0; i < len; ++i) {
            bool now = s[i] - 'a';
            if (trie[p][now] == 0) return 0;
            p = trie[p][now];
        }
        return isend[p];
    }
    

    应用

    本文主要谈应用字典树解题,如果上面的讲解不明白,可以自行Baidu一下qwq。

    例题一 于是他错误的点名开始了

    查看原题-洛谷P2580

    这题是字典树最基本的运用,查询存在性和重复性。

    把所有化学生的姓名插入字典树,再在每次教练点名时,查询。

    例题二 The XOR Largest Pair

    查看原题-LibreOJ#10050

    这题看似和字典树没啥关系,也找不到可以插入的字符串。

    最容易想到的做法就是暴力,两两枚举xor,时间复杂度 (O(n^2))

    其实这里可以把每个数的二进制值插入字典树中,

    枚举每个数,在字典树中查询与它尽量二进制按位尽量相反的树。

    code:

    void insert(int x) {
        int p = 1;
        for (int i = 30; i >= 0; --i) {
            bool now = (x & (1 << i));
            if (trie[p][now] == 0) trie[p][now] = ++m;
            p = trie[p][now];
        }
        isend[p] = true;
    }
    
    int lookup(int x) {
        int res = 0;
        int p = 1;
        for (int i = 30; i >= 0; --i) {
            bool now = (x & (1 << i));
            now = !now;
            if (trie[p][now]) { // 成功匹配,此位相反
                res |= (1 << i);
                p = trie[p][now];
            } else { // 匹配失败,这一位只能相等
                p = trie[p][!now];
            }
        }
        return res;
    }
    

    例题三 最长XOR序列

    查看题目-暂无题目qwq

    描述:还是给你一个序列,要求这个序列的某个子序列的异或和最大,求这个最大值。

    (注:子序列是连续的,子串才是不连续的。

    异或和是指连续异或的值,如4,7,10的异或和是4 xor 7 xor 10

    这里要用到异或的几个性质:

    1. (a operatorname{xor} b operatorname{xor} c=(a operatorname{xor} b)operatorname{xor} c=aoperatorname{xor}(boperatorname{xor}c))

    2. (a operatorname{xor} a=0)

    3. (aoperatorname{xor}0=a)

  • 相关阅读:
    Aurora 数据库支持多达五个跨区域只读副本
    Amazon RDS 的 Oracle 只读副本
    Amazon EC2 密钥对
    DynamoDB 读取请求单位和写入请求单位
    使用 EBS 优化的实例或 10 Gb 网络实例
    启动 LAMP 堆栈 Web 应用程序
    AWS 中的错误重试和指数退避 Error Retries and Exponential Backoff in AWS
    使用 Amazon S3 阻止公有访问
    路由表 Router Table
    使用MySQLAdmin工具查看QPS
  • 原文地址:https://www.cnblogs.com/szdytom/p/trie_tree.html
Copyright © 2011-2022 走看看