Trie——解决字符串搜索、异或最值问题

  • 在说到Trie之前,我们设想如下问题:

给我们1e5个由小写字母构成的不重复的字符串,每个字符串长度不超过6,之后是1e5次查询操作,每次给我们一个字符串,要求我们判断这个字符串是否出现过,如果是则求出它是多少个其他的字符串的前缀,并在之后的操作中无视这个字符串(删除)。

  • 查询是否出现这个可以用set或者hash,但是前缀,,其实也有办法,但是这里要介绍的方法是使用一种易于理解的数据结构——Trie

建立Trie

  • 字典树Trie的结构比较自然,如对于字符串集合{"abca", "ab", "bcd", "abcde", "bcde", "bcdf"},可以建立一棵这样的Trie:

可知:

- 每一条边代表一个字符
- 节点不为0代表从根节点到此为一个完整的字符串

实现的方法也比较简单,建立一棵单向树,每个节点都有

  • 26个子节点(所有小写字母);

  • 一个isstr,bool值,代表这里是否为一个字符串的结束

  • 一个vis,int值,代表到这里已经有多少个字符串遍历过(是多少字符串的前缀)

一开始树为空,我们每得到一个字符串,就从它的第一个字符开始,从根节点遍历,没有对应的节点就创建,同时把所经过的节点的vis值加一,到最后字符串终止时,在终止的节点处置isstr为true。

更多操作

1.查询

从树的形状就可以看出,这是一棵专门查询字符串存在与否的数据结构(同时也付出了巨大的空间代价)。查询操作很简单,从根节点开始,按照要查询的字符串的每一位来遍历,如果遇到空节点或者终止时的节点的isstr为false,则字符串不存在,否则存在。

2.查询某个串是多少个字符串的前缀

这个就是读取要查询的字符串的终止节点的vis值即可

3.删除某个字符串

首先查询成功之后,我们从底部开始回溯删除这个串的信息,将终止节点的isstr置为false,同时将路过的vis值减一,如果vis值减为0则将将此节点在其父节点中删除即可。

01Trie解决xor最值问题

原题链接

题意

给我们一个序列A和序列B,要求我们找到B序列的一种排列,使得

\[C_i \quad xor \quad B_i == A_i
\]

中的序列C字典序最小,并输出序列C,长度<=3e5,每个数小于2^30

思路

  • 首先按照运算规则C xor B == A意味着A xor B == C 也就是说 寻找一种B的排列,使得A逐个与B异或的结果的字典序最小

  • 3e5基本不可能在其他操作中间搞什么排序了,应该从异或运算的结果出发,我们追求结果的字典序最小,也就是说,对于每个Ai,我们都要找到一个Bj,使得其异或结果最小。这个如果直接找的话,是比较难的。但是如果使用Trie的话,可以直接求得每一个Ai的最小结果,方法如下:

    • 对B序列建立一棵只包含01字符的Trie(也就是二叉树),我们规定A与B的每一个数都是30位二进制数,左边补零,从左边的第一位开始建树。

    • B序列的01Trie建好之后,对A序列从1到n每个数都按位在Trie中遍历,一开始先设ans为0,之后优先走与当前自己的二进制位相同的边,如果没有则让ans或上这一位的1。(确保ans尽可能地小)

    • 之后输出这个ans,并将走过的路线所代表的Bi删除掉就可以

  • 可以看出时间复杂度为

    \[O(30*n)
    \]

  • 对空间复杂度来说,不要使用满二叉树的存储方式,使用动态开点的方式,空间复杂度不超过

    \[O(30*n)
    \]

01Trie代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; int n;
int aa[10000005][2] = {{0}}, vv[10000005][2] = {{0}}, co = 1;
int A[300005] = {0}; void add(int x)
{
int o = 1;
for (int i = 29; i >= 0; --i)
{
int bitt = (x >> i) & 1;
if (!aa[o][bitt])
{
aa[o][bitt] = ++co;
}
++vv[o][bitt];
o = aa[o][bitt];
}
} int trie(int x)
{
int o = 1, ans = 0;
for (int i = 29; i >= 0; --i)
{
int bitt = (x >> i) & 1;
if (vv[o][bitt])
{
--vv[o][bitt];
o = aa[o][bitt]; }
else
{
--vv[o][bitt ^ 1];
o = aa[o][bitt ^ 1];
ans |= (1 << i);
}
}
return ans;
} int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &A[i]);
}
for (int i = 1; i <= n; ++i)
{
int xx;
scanf("%d", &xx);
add(xx);
}
for (int i = 1; i < n; ++i)
{
printf("%d ", trie(A[i]));
}
printf("%d", trie(A[n]));
return 0;
}

Trie——解决字符串搜索、异或最值问题的更多相关文章

  1. C#下利用正则表达式实现字符串搜索功能的方法(转)

    关键字:正则表达式.元字符.字符串.匹配: 1.正则表达式简介:正则表达式提供了功能强大.灵活而又高效的方法来处:.NET框架正则表达式并入了其他正则表达式实现的: 2.字符串搜索:正则表达式语言由两 ...

  2. 如果不空null并且不是空字符串才去修改这个值,但这样写只能针对字符串(String)类型,如果是Integer类型的话就会有问题了。 int i = 0; i!=''。 mybatis中会返回tr

    mybatis 参数为Integer型数据并赋值0时,有这样一个问题: mybatis.xml中有if判断条件判断参数不为空时,赋值为0的Integer参数被mybatis判断为空,因此不执行< ...

  3. Linux常用命令学习2---(文件搜索命令locate find、命令搜索命令whereis which、字符串搜索命令grep、帮助命令man)

     1.文件搜索命令:locate [文件名]    在后台数据库中按文件名搜索,搜索速度比find快,耗费资源更少    例子:locate test.txt,就会显示文件名包含 test.txt的所 ...

  4. gerrit session expired 怎么解决,搜索未果

    gerrit session expired,怎么解决,搜索未果

  5. jsoncpp封装和解析字符串、数字、布尔值和数组

    使用jsoncpp进行字符串.数字.布尔值和数组的封装与解析. 1)下载jsoncpp的代码库 百度网盘地址 :http://pan.baidu.com/s/1ntqQhIT 2)解压缩文件 json ...

  6. C#入门篇6-7:字符串操作 看看字符串的特殊之处 值类型与引用类型的区别

    //看看字符串的特殊之处值类型与引用类型的区别 public static void CompareString(string stra, string strb, int i) { #region ...

  7. 解决dede搜索页面只能显示10条信息解决方案

    解决dede搜索页面只能显示10条信息解决方案,感觉显示的信息太少,这时就要想办法去解决一下.看看有什么好办法来解决一下这个问题. dede搜索页模板中,默认只能显示10条记录. 打开dede搜索页模 ...

  8. 【ToolGood.Words】之【StringSearch】字符串搜索——基于BFS算法

    字符串搜索中,BFS算法很巧妙,个人认为BFS算法效率是最高的. [StringSearch]就是根据BFS算法并优化. 使用方法: string s = "中国|国人|zg人|fuck|a ...

  9. xsank的快餐 » Python simhash算法解决字符串相似问题

    xsank的快餐 » Python simhash算法解决字符串相似问题 Python simhash算法解决字符串相似问题

随机推荐

  1. 【SEED Labs】DNS Rebinding Attack Lab

    Lab Overview 实验环境下载:https://seedsecuritylabs.org/Labs_16.04/Networking/DNS_Rebinding/ 在这个实验中模拟的物联网设备 ...

  2. const变量的修改

    int main(){ const char a[]="hello world"; char *aa=(char *)a; printf("\nthe a address ...

  3. 黎活明8天快速掌握android视频教程--21_监听ContentProvider中数据的变化

    采用ContentProvider除了可以让其他应用访问当前的app的数据之外,还有可以实现当app的数据发送变化的时候,通知注册了数据变化通知的调用者 其他所有的代码都和第20讲的一样,不同的地方看 ...

  4. 黎活明8天快速掌握android视频教程--15_采用Pull解析器解析和生成XML内容

    1.该项目主要有下面的两个作用 (1)将xml文件解析成对象的List对象,xml文件可以来自手机本地,也可以来自服务器返回的xml数据 (2)强list对象保存成xml文件,xml保存到手机的内存卡 ...

  5. 微信小程序点击保存图片到本地相册——踩坑

    在微信小程序中要保存图片到本地相册,需要获取相册权限. 总之整个功能实现下来需要如下几个小程序的API:wx.getSetting,wx.authorize,wx.openSetting,wx.dow ...

  6. Redis五种数据类型应用场景

    目录 1.1 回顾 2.1 应用场景 2.1.1 String 2.1.2 Hash 2.1.3 List 2.1.4 Zet 2.1.5 zset 3.1 小结 1.1 回顾 Redis的五种数据类 ...

  7. USACO 2020 OPEN Silver Problem 3. The Moo Particle

    题意: 解法: 首先给出在本题中连通和连通块的定义: 连通: 两个粒子a,b连通,当且仅当ax≤bx.ay≤by或者bx≤ax.by≤ay. 如图,A,B两粒子是连通的,而C.D不是. 可以看出,本题 ...

  8. 命令 关闭SElinux

    # sed -i 's/^SELINUX=.*$/SELINUX=disabled/g' /etc/selinux/config

  9. python数据结构(一)

    collections --容器数据类型,collections模块包含了除内置类型list,dict和tuple以外的其他容器数据类型. Counter 作为一个容器可以追踪相同的值增加了多少次 # ...

  10. 基于C#实现DXF文件读取显示

    工控领域的制图软件仍然以AutoCAD为主,很多时候我们希望上位机软件可以读取CAD的图纸文件,从而控制设备按照绘制的路线进行运行,今天给大家分享的是如何使用C#读取DXF文件并进行显示. 公众号:[ ...