C++字典树算法:找出强数对的最大异或值 II

涉及知识点

数学 字典树

题目

给你一个下标从 0 开始的整数数组 nums 。如果一对整数 x 和 y 满足以下条件,则称其为 强数对 :
|x - y| <= min(x, y)
你需要从 nums 中选出两个整数,且满足:这两个整数可以形成一个强数对,并且它们的按位异或(XOR)值是在该数组所有强数对中的 最大值 。
返回数组 nums 所有可能的强数对中的 最大 异或值。
注意,你可以选择同一个整数两次来形成一个强数对。
示例 1:
输入:nums = [1,2,3,4,5]
输出:7
解释:数组 nums 中有 11 个强数对:(1, 1), (1, 2), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (3, 5), (4, 4), (4, 5) 和 (5, 5) 。
这些强数对中的最大异或值是 3 XOR 4 = 7 。
示例 2:
输入:nums = [10,100]
输出:0
解释:数组 nums 中有 2 个强数对:(10, 10) 和 (100, 100) 。
这些强数对中的最大异或值是 10 XOR 10 = 0 ,数对 (100, 100) 的异或值也是 100 XOR 100 = 0 。
示例 3:
输入:nums = [500,520,2500,3000]
输出:1020
解释:数组 nums 中有 6 个强数对:(500, 500), (500, 520), (520, 520), (2500, 2500), (2500, 3000) 和 (3000, 3000) 。
这些强数对中的最大异或值是 500 XOR 520 = 1020 ;另一个异或值非零的数对是 (5, 6) ,其异或值是 2500 XOR 3000 = 636 。
**参数范围:
1 <= nums.length <= 5 * 104
1 <= nums[i] <= 220 - 1

代码及分析

自己封装的类

class CBitTrieNode
{
public:
CBitTrieNode* Add(bool b)
{
if (nullptr == m_pNode[b])
{
m_pNode[b] = new CBitTrieNode();
}
m_pNode[b]->m_iNum++;
return m_pNode[b];
}
const CBitTrieNode* Get(bool b)const
{
if ((nullptr != m_pNode[b])&&(m_pNode[b]->m_iNum > 0 ))
{
return m_pNode[b];
}
return nullptr;
}
CBitTrieNode* SubNum(bool b)
{
if (nullptr == m_pNode[b])
{
return nullptr;
}
m_pNode[b]->m_iNum–;
return m_pNode[b];
}
protected:
int m_iNum = 0;
CBitTrieNode* m_pNode[2] = { nullptr,nullptr };
};
template<class TData = int ,int iBitNum=31 >
class CBitTrie
{
public:
void Add(TData data)
{
CBitTrieNode* pNode = &m_root;
for (int i = iBitNum - 1; i >= 0; i–)
{
pNode = pNode->Add(data&(1 << i));
}
m_mValueNum[data]++;
}
void Erase(TData data)
{
m_mValueNum[data]–;
CBitTrieNode* pNode = &m_root;
for (int i = iBitNum - 1; i >= 0; i–)
{
pNode = pNode->SubNum(data & (1 << i));
}
}
CBitTrieNode m_root;
protected:
std::unordered_map<TData, int> m_mValueNum;
};

分析

只需要考虑x<y

x,y和y,x结果完全一样。如果x等于y,其结果为0,我们将结果的初始值设置为0,就可以把重复内数据删除。

精简公式

|x - y| <= min(x, y) 因为x<y,所以 y-x <= x => y <=2x

时间复杂度

总时间复杂度:O(nlogn)。枚举x,时间复杂度O(n)。增加、删除、查询字典树,时间复杂度O(logn)。

变量解释

m_trie记录所有符合条件的y:一,x < y。二,y<=2x。要做两件事:一,删除<=x的y,每次枚举x的时候,只需要删除等于x的y,小于x的y之前已经删除。二,增加新的y。
iCurx 和所有符合条件的y的最大异或和

如何从众多y中选择x

最高位是1优先选择最高位为0
最高位是0优先选择最高位为1
这样最高位为1
次高为类似

注意

m_trie.Erase(nums[left]); nums[left]一定符合条件,所以一定可以删除。

核心代码

class Solution {
public:int maximumStrongPairXor(vector<int>& nums) {		//排序并删除重复std::sort(nums.begin(), nums.end());nums.erase(std::unique(nums.begin(), nums.end()), nums.end());m_c = nums.size();int right = 0;int iRet = 0;//自已异或自己为0for (int left = 0; left < nums.size(); left++){//加入所有符合要求的y(nums[right])while ((right < m_c) && (nums[left] * 2 >= nums[right])){//是强数对m_trie.Add(nums[right]);right++;}m_trie.Erase(nums[left]);//字典树中查询int iCur = 0;const CBitTrieNode* ptr = &m_trie.m_root;for (int i = iBitNum-1; (nullptr != ptr) && (i >= 0); i--){const bool b = nums[left] & (1 << i);auto tmp = ptr->Get(!b);if (nullptr != tmp){iCur += (1 << i);ptr = tmp;continue;}ptr = ptr->Get(b);}iRet = max(iRet, iCur);}return iRet;}int m_c;	static const int iBitNum = 20;CBitTrie<int, iBitNum>  m_trie;
};

测试用例

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
Assert(v1[i], v2[i]);
}
}

int main()
{
vector nums;
int res;
{
nums = { 1 };
res = Solution().maximumStrongPairXor(nums);
Assert(0, res);
}
{
nums = { 1 ,2 };
res = Solution().maximumStrongPairXor(nums);
Assert(3, res);
}
{
nums = { 10 ,100 };
res = Solution().maximumStrongPairXor(nums);
Assert(0, res);
}
{
nums = { 2,2,1,1 };
res = Solution().maximumStrongPairXor(nums);
Assert(3, res);
}
{
nums = { 1 ,2, 3,4,5 };
res = Solution().maximumStrongPairXor(nums);
Assert(7, res);
}
{
nums = { 500, 520, 2500, 3000 };
res = Solution().maximumStrongPairXor(nums);
Assert(1020, res);
}

//CConsole::Out(res);

}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

| 洒家想对大家说的话
|
|-|
|闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。|
| 墨家名称的来源:有所得以墨记之。 |
|如果程序是一条龙,那算法就是他的是睛|

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/141485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql主从复制-使用心得

文章目录 前言环境配置主库从库 STATEMENTbinloggtidlog-errorDistSQL总结 前言 mysql 主从复制使用感受&#xff0c;遇到一些问题的整理&#xff0c;也总结了一些排查问题技巧。 环境 mysql5.7 配置 附&#xff1a;千万级数据快速插入配置可以参考&#xff1a;mysql千万数…

HarmonyOS应用开发者高级认证(88分答案)

看好选择题&#xff0c;每个2分多答对2个刚好88分&#xff0c;祝你顺利。 其它帮扶选择题。 一、判断 只要使用端云一体化的云端资源就需要支付费用&#xff08;错&#xff09;所有使用Component修饰的自定义组件都支持onPageShow&#xff0c;onBackPress和onPageHide生命周期…

vue3配置环境变量,小白简单易学

环境变量的意义就是防止我们更新打包的时候写错变量&#xff0c;合并代码这些一系列问题 首先看看效果 左边是本地测试环境&#xff0c;右边是打包后的生产环境&#xff0c;写这个环境变量的好处就是&#xff0c;你在本地开发的时候变量随便改&#xff0c;不会影响生产环境&am…

07【保姆级】-GO语言的程序流程控制【if switch for while 】

之前我学过C、Java、Python语言时总结的经验&#xff1a; 先建立整体框架&#xff0c;然后再去抠细节。先Know how&#xff0c;然后know why。先做出来&#xff0c;然后再去一点点研究&#xff0c;才会事半功倍。适当的囫囵吞枣。因为死抠某个知识点很浪费时间的。对于GO语言&a…

2024 款:最新前端技术趋势

Hello&#xff0c;大家好&#xff0c;我是 Sunday。 上一次的时候聊了 那么些已经落后的前端开发技术 。但是光知道什么技术落后了是不够的&#xff0c;咱们还得知道 前端最新的技术趋势是什么。所以&#xff0c;今天这篇文章&#xff0c;咱们就来聊一聊&#xff0c;2023 最新…

Spring后端HttpClient实现微信小程序登录

这是微信官方提供的时序图。我们需要关注的是前后端的交互&#xff0c;以及服务端如何收发网络请求。 小程序端 封装基本网络请求 我们先封装一个基本的网络请求。 const baseUrl"localhost:8080" export default{sendRequsetAsync } /* e url&#xff1a;目标页…

对比国内主流开源 SQL 审核平台 Yearning vs Archery

Yearning, Archery 和 Bytebase 是目前国内最主流的三个开源 SQL 审核平台。其中 Yearning 和 Archery 是社区性质的项目&#xff0c;而 Bytebase 则是商业化产品。通常调研 Bytebase 的用户也会同时比较 Yearning 和 Archery。 下面我们就来展开对比一下 Yearning 和 Archery…

DRAM和SRAM

特点 Static Random Access Memory&#xff1a;速度快、存储一位需要元器件更多、功耗较大、集成度低、更贵 Dynamic Random Access Memory&#xff1a;容量大、需刷新、附属电路更复杂、功耗较小、集成度高 存储位元 SRAM DRAM 逻辑结构 SRAM 典型的SRAM芯片有6116&am…

Layer 2 真的为以太坊扩容了吗?

构建一个安全、对用户友好的去中心化网络的愿景&#xff0c;依赖于关键基础设施的发展。这个愿景由一个共享的经济框架支持&#xff0c;得到了亿万人的拥护。Layer 2 的扩展解决方案在构建这一基础和增强以太坊的能力方面起着至关重要的作用。这些项目相互协作&#xff0c;形成…

数据结构—数组栈的实现

前言&#xff1a;各位小伙伴们我们前面已经学习了带头双向循环链表&#xff0c;数据结构中还有一些特殊的线性表&#xff0c;如栈和队列&#xff0c;那么我们今天就来实现数组栈。 目录&#xff1a; 一、 栈的概念 二、 栈的实现 三、 代码测试 栈的概念&#xff1a; 栈的概念…

【PG】PostgreSQL 预写日志(WAL)、checkpoint、LSN

目录 预写式日志&#xff08;WAL&#xff09; WAL概念 WAL的作用 WAL日志存放路径 WAL日志文件数量 WAL日志文件存储形式 WAL日志文件命名 WAL内容 检查点&#xff08;checkpoint&#xff09; 1 检查点概念 2 检查点作用 触发检查点 触发检查点之后数据库操作 设置合…

数据结构之队列

目录 引言 队列的概念与结构 队列的实现 定义 初始化 销毁 入队 判断队列是否为空 出队 获取队头元素 获取队尾元素 检测队列中有效元素个数 元素访问 源代码 queue.h queue.c test.c 引言 数据结构之路经过栈后&#xff0c;就来到了与栈联系紧密的兄弟—…

RabbitMq防止消息丢失

RabbitMq防止消息丢失 消息的传递路径出现消息丢失的位置解决 消息的传递路径 消息发送方 --> MQ --> 消息消费方 出现消息丢失的位置 消息发送方: 消息传输过程中丢失MQ: MQ收到消息后,存在内存中,还未被消费就宕机了,导致数据丢失消息消费方: 消息到达消费方后, 服务…

Docker安装详细步骤及相关环境安装配置(mysql、jdk、redis、自己的私有仓库Gitlab 、C和C++环境以及Nginx服务代理)

目录 一、从空白系统中克隆Centos7系统 二、使用xshell连接docker_tigerhhzz虚拟机​编辑 三、在CentOS7基础上安装Docker容器 四、在Docker中进行安装Portainer 4.1、在Docker中安装MySQL 4.2、在Docker中安装JDK8&#xff0c;安装Java环境 4.3、Docker安装redis&#…

Maya v2024(3D动画制作软件)

Maya 2024是一款三维计算机图形动画制作软件。它被广泛应用于电影、电视、游戏、动画等领域中&#xff0c;用于创建各种三维模型、场景、特效和动画。 以下是Maya的主要特点&#xff1a; 强大的建模工具&#xff1a;Maya提供了各种建模工具&#xff0c;如多边形建模、NURBS建模…

时序数据库 TDengine + 高级分析软件 Seeq,助力企业挖掘时序数据潜力

作为一款制造业和工业互联网&#xff08;IIOT&#xff09;高级分析软件&#xff0c;Seeq 支持在工艺制造组织中使用机器学习创新的新功能。这些功能使组织能够将自己或第三方机器学习算法部署到前线流程工程师和主题专家使用的高级分析应用程序&#xff0c;从而使单个数据科学家…

20.有效的括号(LeetCode)

思路&#xff1a;用栈的后进先出的特性&#xff0c;来完成题目的要求 因为C有库&#xff0c;可以直接用&#xff0c;而C语言没有&#xff0c;所以我们直接把写好的栈拷贝上来用。 首先&#xff0c;完成框架的搭建 其次&#xff0c;再实现循环内的部分。1.左括号入栈 2.右括…

react函数式组件props形式子向父传参

父组件中定义 子组件中触发回调传值 import { useState } from "react"; function Son(params) {const [count, setCount] useState(0);function handleClick() {console.log(params, paramsparamsparamsparamsparamsparams);params.onClick(111)setCount(count 1…

Rust-使用dotenvy加载和使用环境变量

系统的开发&#xff0c;测试和部署离不开环境变量&#xff0c;今天分享在Rust的系统开发中&#xff0c;使用dotenvy来读取和使用环境变量。 安装 cargo add dotenvy dotenv_codegen 加载环境变量 use dotenvy::dotenv;fn main() {dotenv().expect(".env不存在");…

TensorFlow学习笔记--(3)张量的常用运算函数

损失函数及求偏导 通过 tf.GradientTape 函数来指定损失函数的变量以及表达式 最后通过 gradient(%损失函数%,%偏导对象%) 来获取求偏导的结果 独热编码 给出一组特征值 来对图像进行分类 可以用独热编码 0的概率是第0种 1的概率是第1种 0的概率是第二种 tf.one_hot(%某标签…