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

news2025/1/12 13:35:05

涉及知识点

数学 字典树

题目

给你一个下标从 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;//自已异或自己为0
		for (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.coloradmin.cn/o/1205970.html

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

相关文章

Mybatis框架——mybatis是什么

第一&#xff0c;mybatis是一个持久层的框架&#xff0c;它支持自定义SQL&#xff0c;存储过程以及高级映射。 mybatis几乎代替了所有的JDBC代码以及设置参数和获取结果集的工作&#xff0c;可以通过简单的XML或者注解来配置和映射原始类型、接口和Java POJO&#xff08;Plain…

webgoat-Challenges

AdminLostpassword 这一题密码藏在logo图片里 请求GET /WebGoat/challenge/logo 搜索admin看到密码&#xff0c;使用账号admin和这个密码登录拿到flag Without password 题目要求&#xff1a;在不知道Larry的密码情况下登录 考虑使用SQL注入 密码输入 123 or 11 -- Admin p…

【数据结构——队列的实现(单链表)】

数据结构——队列的实现&#xff08;单链表&#xff09; 一.队列1.1队列的概念及结构 二.队列的实现2.1 头文件的实现——&#xff08;Queue.h&#xff09;2.2 源文件的实现—— &#xff08;Queue.c&#xff09;2.3 源文件的实现—— &#xff08;test.c&#xff09; 三.队列的…

20.1 platform 设备驱动

一、Linux 驱动的分离与分层 1. 驱动的分隔和分离 现在有三个平台&#xff0c;A、B 和 C&#xff0c;这三个平台都有 MPU6050 设备。编写最简单的驱动框架如下图&#xff1a; 每个平台下都有一个主机驱动和设备驱动&#xff0c;主机驱动是必要的&#xff0c;因为不同的平台 I2…

【算法】新的开始(Kruskal算法,虚拟源点)

题目 发展采矿业当然首先得有矿井&#xff0c;小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井&#xff0c;但他似乎忘记了考虑矿井供电问题。 为了保证电力的供应&#xff0c;小 FF 想到了两种办法&#xff1a; 在矿井 i 上建立一个发电站&#xff0c;费用…

【计算机网络笔记】IP子网划分与子网掩码

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

项目笔记记录

一、node下载版本报错&#xff1a;npm install --legacy-peer-deps 二、Scheduled: 任务自动化调度 Scheduled 标记要调度的方法的注解&#xff0c;必须指定 cron&#xff0c;fixedDelay或fixedRate属性之一 fixedDelay&#xff1a;固定延迟 延迟执行任务&#xff0c;任务在…

sqli-labs关卡17(基于post提交的单引号闭合的报错盲注)通关思路

文章目录 前言一、回顾上一关知识点二、靶场第十四关通关思路1、判断注入点2、爆显位3、爆数据库名4、爆数据库表5、爆数据库列6、爆数据库关键信息 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;不…

使用validator实现枚举类型校验

使用validator实现枚举类型校验 前言&#xff1a; 在前端调用后端接口传递参数的过程中&#xff0c;我们往往需要对前端传递过来的参数进行校验&#xff0c;比如说我们此时需要对用户的状态进行更新&#xff0c;而用户的状态只有正常和已删除&#xff0c;并且是在代码中通过枚…

20.有效的括号(LeetCode)

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

键盘接受一串字符到BUF为首地址的字节单元中,要求用下列方法分别编程,将它们以相反的次序显示在屏幕的下一行中

(1).按地址从尾向前依次显示。 (2)利用堆栈反向显示。 (3).利用交换的方法反序后&#xff0c;然后显示&#xff1a;即ai<——>aj

通过流量分析查看业务系统运行和访问情况

在当今数字化时代&#xff0c;应用程序的运行和访问情况对于企业和组织来说至关重要。无论是在线销售平台、移动应用还是企业内部系统&#xff0c;应用的性能和可用性直接影响着用户体验、业务流程以及组织效率。因此&#xff0c;对应用的运行和访问情况进行全面分析和评估&…

网络运维Day14

监控概述 监控的目的 报告系统运行状况每一部分必须同时监控内容包括吞吐量、反应时间、使用率等提前发现问题进行服务器性能调整前&#xff0c;知道调整什么找出系统的瓶颈在什么地方 监控的资源类别 公开数据 Web、FTP、SSH、数据库等应用服务TCP或UDP端口 私有数据 CPU、内…

Python高级语法----使用Python进行模式匹配与元组解包

文章目录 1. 模式匹配的新特性2. 高级元组解包技巧3. 数据类的匹配与应用1. 模式匹配的新特性 Python自3.10版本起引入了结构化模式匹配的新特性,这是一种强大的工具,允许开发者用更清晰、更直观的方式处理数据结构。模式匹配类似于其他编程语言中的switch-case语句,但它更…

【PC】开发者日志:竞技比赛验证系统强化

各位玩家大家好&#xff01;欢迎收看本期开发者日志。 在11月1日发布的第26赛季第2轮更新公告中&#xff0c;我们提到了有关强化比赛验证系统的内容。想必各位玩家一定会对我们加强验证系统的背景和意图感到好奇&#xff0c;为此我们想通过今天这篇反作弊开发者日志来向大家更详…

Linux socket编程(2):socket函数介绍及C/S模型代码实现

上一节简单介绍了一下套接字、字节序和地址结构体的概念&#xff0c;算是对socket有一个入门的了解。这一节就实现一个客户端-服务端的代码&#xff0c;从这个例子中来学习socket函数的使用。 文章目录 1 客户端/服务端模型2 套接字函数2.1 socket:创建套接字2.2 bind:绑定套接…

设计模式之适配器(Adapter)

Adapter Wapper 接口转换器 如果一个类不能直接访问另一个类的时候&#xff0c;中间加一个Adapter转换器就能访问了 常见例子: 电压转接头 java.io jdbc-odbc bridge(不是桥接模式) ASM Transformer java io里面的读文件操作: FileInputStream是字节流读文件&#xff0c;就像…

Python高级语法----Python C扩展与性能优化

文章目录 1. 编写Python C扩展模块示例代码编译和运行运行结果2. 利用Cython优化性能示例代码编译和运行运行结果3. Python性能分析工具示例代码分析结果1. 编写Python C扩展模块 Python C扩展模块允许你将C语言代码集成到Python程序中,以提高性能。这对于计算密集型任务特别…

ppt中的字体,如何批量替换?

想要将PPT中的文字全部更换&#xff0c;有什么方便的方法吗&#xff1f;今天分享两个方法&#xff0c;一键修改ppt文件字体。 方法一&#xff1a; 找到功能栏中的编辑选项卡&#xff0c;点击替换 – 替换字体&#xff0c;在里面选择我们想要替换的字体就可以了。 方法二&…