2022-11-13 Acwing每日一题
本系列所有题目均为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每日一题的更多相关文章
- [ 9.13 ]CF每日一题系列—— 340A GCD & LCM
Description: [ 着实比较羞愧,都想着去暴力,把算法(方法)也忘了] A只涂x,2x,3x……,B只涂y,2y,3y……问你A和B共同涂的墙的个数 Solution: 就是求x和y的lcm ...
- CISP/CISA 每日一题 13
监控信息系统人员所提供服务的效率和效果的工具: 1.例外报告:识别所有没有成功完成的或出了故障的应用 2.作业重运行报告:大多数异常终止作业都会导致重起 3.操作员问题报告:记录计算机运行问题及解决方 ...
- CISP/CISA 每日一题 11
CISA 每日一题(答) 一个合理建造的数据仓库应当支持下列三种基本的查询格式: 1.向上溯源和向下溯源——向上溯源是对数据进行总计:向下溯源是将数据进行细化: 2.交叉溯源——通过通用属性访问数据仓 ...
- 老男孩IT教育-每日一题汇总
老男孩IT教育-每日一题汇总 第几天 第几周 日期 快速访问链接 第123天 第二十五周 2017年8月25日 出现Swap file….already exists以下错误如何解决? 第122天 2 ...
- CISP/CISA 每日一题 五
CISA 每日一题(答) 信息系统审计师要确认系统变更程序中的: 1.变更需求应有授权.优先排序及跟踪机制: 2.日常工作手册中,明确指出紧急变更程序: 3.变更控制程序应同时为用户及项目开发组认可: ...
- [每日一题]面试官问:谈谈你对ES6的proxy的理解?
[每日一题]面试官问:谈谈你对ES6的proxy的理解? 关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- 【python】Leetcode每日一题-寻找旋转排序数组中的最小元素
[python]Leetcode每日一题-寻找旋转排序数组中的最小元素 [题目描述] 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组nums ...
- 【JavaScript】【dp】Leetcode每日一题-解码方法
[JavaScript]Leetcode每日一题-解码方法 [题目描述] 一条包含字母 A-Z 的消息通过以下映射进行了 编码 : 'A' -> 1 'B' -> 2 ... 'Z' -& ...
- [LeetCode每日一题]153.寻找旋转排序数组中的最小值
[LeetCode每日一题]153.寻找旋转排序数组中的最小值 问题 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组 nums = [0,1, ...
- 【python】Leetcode每日一题-逆波兰表达式求值
[python]Leetcode每日一题-逆波兰表达式求值 [题目描述] 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说 ...
随机推荐
- Linux_ps总结
ps命令用于监测进程的工作情况.进程是一直处于动态变化中,而ps命令所显示的进程工作状态时瞬间的 使用方式: ps [options] 常用参数 -A 显示所有进程 -a 显示现行终端机下的所有进程, ...
- python3实现:进程遇Error定时重启
import os import time # 停止HFish def stopHFish(): # while True: try: # 找到HFish进程号 HFish_id = int(os.p ...
- 获取客户端访问真实 IP
转载自:https://www.qikqiak.com/post/get-client-realip/ 通常,当集群内的客户端连接到服务的时候,是支持服务的 Pod 可以获取到客户端的 IP 地址的, ...
- ceph安装Dashboard并开启Object Gateway管理功能
安装配置dashboard Ceph-Dashboard 是用 Python 开发的一个 Ceph 的监控面板,用来监控 Ceph 的运行状态.同时 提供 REST API 来访问状态数据. 低版本的 ...
- Beats: 使用 Filebeat 进行日志json结构化 - Python
文章转载自:https://elasticstack.blog.csdn.net/article/details/106688240
- MongoDB 的用户和角色权限
副本和分片集群的安全设置参考这个:高级:https://files.cnblogs.com/files/sanduzxcvbnm/mongodb_advance.pdf 默认情况下,MongoDB实例 ...
- 使用Gitlab的CI/CD功能自动化推送docker镜像到Nexus仓库出现的问题
在服务器中可以直接使用命令行登录,推送docker镜像等 但是在使用Gitlab的CI/CD功能中,gitlab-ci.yml文件执行过程中出现如下错误: 原因分析: 服务器上之前使用命令行登陆过Ne ...
- ERP 系统最重要的是什么?
ERP系统最重要的就是内部业务逻辑,这也是ERP复杂.专业性的体现!ERP系统可以算是当今最复杂的应用系统,也是最昂贵的,头部厂商一套系统动辄上千万,实施费用也常常达到千万级,实施周期动辄半年一年的, ...
- 聊聊Linux中CPU上下文切换
目录 什么是CPU上下文 CPU上下文切换 上一任务的CPU上下文保存在哪? 进程上下文切换 内核空间和用户空间 top命令查看CPU资源 系统调用 进程上下文切换 和 系统调用的区别? 进程切换的常 ...
- NLP之基于Bi-LSTM和注意力机制的文本情感分类
Bi-LSTM(Attention) @ 目录 Bi-LSTM(Attention) 1.理论 1.1 文本分类和预测(翻译) 1.2 注意力模型 1.2.1 Attention模型 1.2.2 Bi ...