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

这篇具有很好参考价值的文章主要介绍了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。
iCur x 和所有符合条件的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

C++字典树算法:找出强数对的最大异或值 II,# 算法题,算法,c++,数据结构,字典树,强数对,异或值,最大文章来源地址https://www.toymoban.com/news/detail-754909.html

到了这里,关于C++字典树算法:找出强数对的最大异或值 II的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode 75 第十三题(1679)K和数对的最大数目

    给一个数组,两个和为K的数为一组,问能凑成几组。 既然一组是两个数,那么我们可以使用双指针分别指向数组首尾,然后再判断能否凑成和为K的组. 在使用双指针寻找之前,我们应当先将数组排序(升序降序都无所谓),我们这里采用C++sort的默认升序. 然后左右指针分别指向数

    2024年02月15日
    浏览(62)
  • 2317.操作后的最大异或和

    首先num[i]^x可以知道 这里可以变成任意一个数字 又有num[i]上上面的数字 所以我们可以扣掉任意位的1把它变成0 答案让我们求异或和 所以只要这一位有1 答案的这一位就有1 我们发现这就是一个按位或运算

    2024年02月08日
    浏览(34)
  • 【每日一题】数组中两个数的最大异或值

    【哈希集合】【位运算-异或和】【数组】【2023-11-04】 421. 数组中两个数的最大异或值 找出数组中两个数的最大异或结果。 一看数据量达到了 1 0 5 10^5 1 0 5 ,那时间复杂度为 O ( n 2 ) O(n^2) O ( n 2 ) 的方法必定超时,因此需要去找 O ( n l o g n ) O(nlogn) O ( n l o g n ) 或者 O ( n ) O(n)

    2024年02月05日
    浏览(37)
  • 【动态规划】 【字典树】C++算法:472 连接词

    视频算法专题 动态规划汇总 字典树 给你一个 不含重复 单词的字符串数组 words ,请你找出并返回 words 中的所有 连接词 。 连接词 定义为:一个完全由给定数组中的至少两个较短单词(不一定是不同的两个单词)组成的字符串。 示例 1: 输入:words = [“cat”,“cats”,“cat

    2024年02月01日
    浏览(44)
  • 简单数学题:找出最大的可达成数字

    来看一道简单的数学题:力扣2769. 找出最大的可达成数字 题目描述的花里胡哨,天花乱坠,但这道题目非常简单。我们最多执行t次操作,只需每次操作都让x-1,让num+1,执行t次操作后,x就变为x+t,num就变成num-t,由于两者相等,有: x+t = num-t 故x = num+2×t。 简单的数学题,一

    2024年02月10日
    浏览(37)
  • OpenCV minMaxLoc()函数找出图像中最小值最大值

    OpenCV 找出图像中最小值最大值函数minMaxLoc的使用 功能:从一个矩阵中找出全局的最大值和最小值。 函数cv::minMaxLoc找出最大和最小元素的值和他们的位置。极值是遍历整个矩阵找到,或者当掩码不是一个空矩阵时,是通过遍历指定矩阵区域找到。 函数不适用于多通道矩阵,

    2024年02月08日
    浏览(40)
  • 有一个 3*4 的矩阵,找出其中值最大的元素,及其行列号

    首先学会输入二维数组;然后知道如何比较求最大值;最后就是格式问题; 3运行代码: 4总结: 感谢各位的阅读,以上就是“C语言怎么有一个 3*4 的矩阵,找出其中值最大的元素,及其行列号”的内容了,经过本文的学习后,相信大家对C语言这一问题有了更深刻的体会,具

    2024年02月04日
    浏览(35)
  • 每日一题411数组中两个数的最大异或值(哈希表、前缀树:实现前缀树)

    LeetCode题目:https://leetcode.cn/problems/maximum-xor-of-two-numbers-in-an-array/   本题使用哈希表方法主要运用到一个定理:异或满足算法交换律。即如果a^b = c,那么必然 b ^ c = a。且数组中的元素都在 [ 0 , 2 31 ) [0,2^{31}) [ 0 , 2 31 ) ,因此可以确定数值的最高位是30位。   因此,可以假设

    2024年02月05日
    浏览(29)
  • [Daimayuan] 异或和(C++,异或,数学)

    给定一个长度为 n n n 的数组 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a 1 ​ , a 2 ​ , ... , a n ​ 。 请你求出下面式子的模 1 e 9 + 7 1e9+7 1 e 9 + 7 的值。 ∑ i = 1 n − 1 ∑ j = i + 1 n ( a i   X O R   a j ) sum_{i=1}^{n-1}{sum_{j=i+1}^{n}{(a_i XOR a_j)}} ∑ i = 1 n − 1 ​ ∑ j = i + 1 n ​ ( a i ​   XOR   a j ​

    2024年02月01日
    浏览(27)
  • C++ 求最大子序列和(贪心算法)

    #include \\\"iostream\\\" #include \\\"vector\\\" using namespace std; class Solution { // 得到一个最大的负数 int isAllLow(vectorint nums){ int max=nums[0]; for (int i = 1; i nums.size(); ++i) { if(maxnums[i]){ max=nums[i]; } } return max; } public: // 求最大子序列 int maxSubArray(vectorint nums) { int sum=0; int maxsum=this-isAllLow(nums); // 如果是一个

    2024年02月07日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包