本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的。同时也希望文章能够让你有所收获,与君共勉!

字典树

今天来学习字典树Trie,Trie树主要支持两个操作,一个是构建Trie时需要的插入操作Insert,另一个是查询操作query

首先来看看什么是字典树Trie,标准的Trie树是字符串组成的,结点是每个字符。图片来自这里

如果是数组来模拟Trie树,就是这样。

既然是树,那么必然存在一个根节点,只不过这里是虚拟节点root,由于小写字符总共有26个,因此总共有26个子节点。数组是这样定义的:son[p][u],其中p可以认为Trie树的深度(从根节点开始算,root为-1层),也可以理解为p服从某种顺序。u是该层所存储的东西,可以是数字也可以是字母(需要映射为数字),而son[p][u]就可以理解为第p层上的字母u的下一层索引(,对于u来说其是固定的,如果存在该字符我们就可以直接使用并通过son[p][u]获得该字符下一层所对应的结点索引),除此之外还有一个idx,它的作用类似一个线性表的在当前位置上的索引,具体作用看代码,这样对于每一个字符就得到了一个具体而准确的定位。

Trie的insert操作:

主要分两种情况,从0开始遍历层数,如果下一层存在该字符,就继续往下走,如果不存在就在下一层该字符处创建新的索引。

Trie的query操作:直接从根节点遍历Trie树,如果某一个字符存在就会自己往下走,否则不存在就可以直接返回。

这就是Trie树的主体,如果对于每个单词,我们想知道他们出现的次数,我们还可以定义cnt数组,来标记第p层存在单词,并且用来表示存在几个单词,而对于是否存在单词我们是在遍历过程中才能发现的,如果不存在某一个单词,那么遍历都不会完成,深度也不会达到p的。

代码表示

#include <iostream>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 100000,idx;
int son[N][26],cnt[N];
int n; void insert(char* s){
int p = 0;
for(int i=0; s[i] ; ++i){
int u = s[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx;
// idx可以看成是深度所形成的线性表的下标,++idx在第一次循环就表示根节点在第0层,第一个结点在第一层
p = son[p][u]; // 就是去下一层
}
cnt[p] ++;
} int query(char *s){
int p = 0;
for(int i=0 ; s[i] ; ++i){
int u = s[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
} int main()
{
cin >> n;
while (n -- ){
char op[2];
char s[N];
scanf("%s%s",op,s);
if(*op == 'I'){
Insert(s); }
else{
cout << Query(s) << endl;;
}
}
return 0;
}

最大异或对

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

输入格式

第一行输入一个整数 N。

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

输出格式

输出一个整数表示答案。

数据范围

1≤N≤105,

0≤Ai<231

输入样例:

3

1 2 3

输出样例:

3

算法原理

遇到题我们先思考暴力怎么求解,然后再针对每一步考虑使用合适的数据结构,对于最大异或对我们先考虑暴力双重循环,两两之间比较异或值,最后选出最大的,核心代码max(res,a[i]^a[j])(其中^是异或运算符),但这个算法的时间复杂度太高,\(O(n^2)\),因此我们需要思考怎么进行优化,我们发现最外层遍历每一个数字不能优化,内层我们需要找出外层固定的这个数字的最大异或值,那么我们就是要针对找到最大异或值这一部分进行优化。我们知道两个数字的异或运算就是对位相反取1,相同取0,如2:10,3:11,2^3:01。那么什么时候取最大值呢,我们发现当每一位都位1时所对应的数字是最大的,高位为1时的数字比低位为1时要更大,所以对位相反时进行异或结果是最大的,我们更希望每一位都相反,因此我们可以先寻找是否存在该数字的最大异或值,这时我们就可以使用Trie树进行寻找,先来看个图就理解为什么要用Trie树啦。图片来自这里



这样做的话找到的不就是该数组存储的所有数中最大的异或值了嘛。

代码实现

#include <iostream>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 3300000;
int son[N][2],a[N]; // 只有0和1两个数,因此是二叉树且默认所有结点的下一层都为第0层(即不存在下一层)
int idx; void insert(int x){ // 插入x的每一位,形成异或树
int p = 0;
for(int i=30; i>=0 ; --i){
int u = x>>i & 1; // 获得x的第i位
if(!son[p][u]){
son[p][u] = ++idx;
}
p = son[p][u];
}
} int search(int x){ // 查询x的最大异或数
int p = 0;
int ans = 0; // 所有位默认为0
for(int i=30; i>=0 ; --i){
int u = x >> i & 1; // 取出第i位
// 判断是否存在对位,如果存在就往下走,否则就走另一个
if(son[p][!u]) {// 存在对位,说明该位可以是最大的,因此该位为1
ans += 1<<i; // 把1向左移到第i位
p = son[p][!u]; // 走的不是原来的位置,而是对位
}
else{ // 不存在对位,所以该位就是0
p = son[p][u]; // ans为0说明当前该位默认为0,直接移到下一位
}
}
return ans;
} int main()
{
int n;
cin >> n;
int x;
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 << endl;
return 0;
}

2022-11-13 Acwing每日一题的更多相关文章

  1. [ 9.13 ]CF每日一题系列—— 340A GCD & LCM

    Description: [ 着实比较羞愧,都想着去暴力,把算法(方法)也忘了] A只涂x,2x,3x……,B只涂y,2y,3y……问你A和B共同涂的墙的个数 Solution: 就是求x和y的lcm ...

  2. CISP/CISA 每日一题 13

    监控信息系统人员所提供服务的效率和效果的工具: 1.例外报告:识别所有没有成功完成的或出了故障的应用 2.作业重运行报告:大多数异常终止作业都会导致重起 3.操作员问题报告:记录计算机运行问题及解决方 ...

  3. CISP/CISA 每日一题 11

    CISA 每日一题(答) 一个合理建造的数据仓库应当支持下列三种基本的查询格式: 1.向上溯源和向下溯源——向上溯源是对数据进行总计:向下溯源是将数据进行细化: 2.交叉溯源——通过通用属性访问数据仓 ...

  4. 老男孩IT教育-每日一题汇总

    老男孩IT教育-每日一题汇总 第几天 第几周 日期 快速访问链接 第123天 第二十五周 2017年8月25日 出现Swap file….already exists以下错误如何解决? 第122天 2 ...

  5. CISP/CISA 每日一题 五

    CISA 每日一题(答) 信息系统审计师要确认系统变更程序中的: 1.变更需求应有授权.优先排序及跟踪机制: 2.日常工作手册中,明确指出紧急变更程序: 3.变更控制程序应同时为用户及项目开发组认可: ...

  6. [每日一题]面试官问:谈谈你对ES6的proxy的理解?

    [每日一题]面试官问:谈谈你对ES6的proxy的理解? 关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

  7. 【python】Leetcode每日一题-寻找旋转排序数组中的最小元素

    [python]Leetcode每日一题-寻找旋转排序数组中的最小元素 [题目描述] 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组nums ...

  8. 【JavaScript】【dp】Leetcode每日一题-解码方法

    [JavaScript]Leetcode每日一题-解码方法 [题目描述] 一条包含字母 A-Z 的消息通过以下映射进行了 编码 : 'A' -> 1 'B' -> 2 ... 'Z' -& ...

  9. [LeetCode每日一题]153.寻找旋转排序数组中的最小值

    [LeetCode每日一题]153.寻找旋转排序数组中的最小值 问题 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组 nums = [0,1, ...

  10. 【python】Leetcode每日一题-逆波兰表达式求值

    [python]Leetcode每日一题-逆波兰表达式求值 [题目描述] 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说 ...

随机推荐

  1. 在Boss直聘上投简历时,怎样保证有新消息时能及时收到

    最近在Boss直聘上投简历,偶尔会有HR给我发消息,不想在电脑上错过这些消息,但我又不能时时刻刻盯着这个页,怎么办呢? 这时,我想起来,之前做过的Chrome插件,如果检测到Boss直聘上新消息数大于 ...

  2. 【读书笔记】C#高级编程 第六章 数组

    (一)同一类型和不同类型的多个对象 如果需要使用同一类型的多个对象,就可以使用数组或集合(后面章讲). 如果需要使用不同类型的多个对象,可以使用Tuple(元组)类型. (二)简单数组 如果需要使用同 ...

  3. 【一月一本技术书】-【MySQL是怎样运行的】- 8月

    mysql 基础 mysql分为 客戶端/服务端 客户端向服务端发送一段文本(mysql语句),服务器处理后向客户端进程返回一段文本. 查询请求执行过程 客户端->处理连接->查询缓存-& ...

  4. Kubernetes容器运行时弃用Docker转型Containerd

    文章转载自:https://i4t.com/5435.html Kubernetes社区在2020年7月份发布的版本中已经开始了dockershim的移除计划,在1.20版本中将内置的dockersh ...

  5. 7.第六篇 二进制安装 kube-apiserver

    文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247483812&idx=1&sn=e6773e56 ...

  6. 使用 Shell 命令 分析服务器日志

    文章转载自:https://mp.weixin.qq.com/s/z2qF571m4JSSVi59D7V71g 1.查看有多少个IP访问: awk '{print $1}' log_file|sort ...

  7. 胎压监测系统(DWS)

    胎压监测系统(DWS)通过监测和比较行驶时各车轮和轮胎的滚动半径和旋转特性,以确定是否一个或多个轮胎明显充气不足,而非直接测量各轮胎的压力. 系统监测到异常时指示灯将点亮,且仪表上出现信息. 必须校准 ...

  8. Solutions:安全的APM服务器访问

    转载自: https://blog.csdn.net/UbuntuTouch/article/details/105527468 APM Agents 访问APM server如果不做安全的设置,那么 ...

  9. Grafana的基本概念

    Grafana基本概念 首先Grafana是一个通用的可视化工具.'通用'意味着Grafana不仅仅适用于展示Prometheus下的监控数据,也同样适用于一些其他的数据可视化需求.在开始使用Graf ...

  10. Fluentd部署:错误排查

    介绍一下排查Fluentd运行时错误的几种方法. 查看日志 如果感觉Fluentd运行异常,请先查看日志.td-agent安装后,默认日志存放在/var/log/td-agent/td-agent.l ...