Maximum XOR of Two Numbers in an Array 数组中两个数的最大异或值

给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。

找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i,  j < 

你能在O(n)的时间解决这个问题吗?

示例:

输入: [3, 10, 5, 25, 2, 8]

输出: 28

解释: 最大的结果是 5 ^ 25 = 28.

思路:这道题阔以说是灰常巧了,在面试的时候如果能自己想出如下的解O(nlogn)而不是O(n^2)的暴力解,那可以说是基本不可能的。这道题如果是O(^2)的解那么非常容易,但是如果想只用一遍扫面数组就做出来就需要很巧的方法,答案我看了很久才看懂。。。(难过ing),所以这道题就直接用注解的方式写出来,不再写思路了。

参考代码:

int findMaximumXOR(vector<int>& nums) {
	int maxResult = 0;
	int mask = 0;
	/*maxResult记录到目前为止我们能异或操作能得到的最大的值. 如果是 11100 在 i = 2的时候,
	before we 那么意味着在到达最后两个bit之前, 11100 是我们能得到的最大异或值, 那么我们就需要探索能不能把剩下的两个bit位也用1来填充到maxResult中。

	这是贪心思想的部分, 为了找到最大的异或值, 我们从最左边开始,也就是从右往左的第32个bit位开始. */
	for(int i = 31; i >= 0; i--) {

		// mask 的规律是  100..000 , 110..000, 111..000,  然后 1111...111
		//在每次循环中,我们只考虑左半部分
		mask = mask | (1 << i);

		unordered_set<int> set;
		for (int num : nums) {

			/* 我们只考虑左半部分, 比如, 如果 i = 2, 那么我们有
			{1100, 1000, 0100, 0000} 来源于 {1110, 1011, 0111, 0010}*/
			int leftPartOfNum = num & mask;
			set.insert(leftPartOfNum);
		}

		// 如果 i = 1 并且在这次迭代之前, 我们得到的maxResult等于1100, 
		// 我们希望maxResult 变成 1110, 所以我希望找到一个能给我这个数即greedyTry的候选者
		int greedyTry = maxResult | (1 << i);

		for (int leftPartOfNum : set) {
			//这是最有技巧的部分, 由异或的基本性质知道,如果:a ^ b = c, 那么 a ^ c = b;
			// 现在我们有 'c', 就是greedyTry, 同时我们也有 'a', 就是leftPartOfNum
			// 如果我们希望方程 a ^ b = c 能成立, 那么我们就需要有 b, 
			// 为了能得到 b, 我们可以做异或的反运算 a ^ c, 如果 a ^ c 在我们的集合set中存在, 那么就证明找到了这个b
			int anotherNum = leftPartOfNum ^ greedyTry;
			if (set.count(anotherNum)) {
				maxResult = greedyTry;
				break;
			}
		}
		// 如果不幸, 我们没有找到 greedyTry,我们依然保留着我们找到的最大值, 
		// 截止到目前的迭代为止, 最大值依旧保留为 1100.
	}
	return maxResult;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值