题目来源:https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/
问题描述
421. Maximum XOR of Two Numbers in an Array
Medium
Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.
Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.
Could you do this in O(n) runtime?
Example:
Input: [3, 10, 5, 25, 2, 8]
Output: 28
Explanation: The maximum result is 5 ^ 25 = 28.
------------------------------------------------------------
题意
求数组nums中两两数字异或的最大值
------------------------------------------------------------
思路
暴力法复杂度O(n^2). 考虑贪心算法,两个数第i位不同,对异或值的贡献为(1<<i),两个数比第i位低的第(i-1)位到第0位,最多对异或值的贡献只有(((1<<(i-1)) + (1<<(i-2)) + .. (1<<0)) = ((1<<i) – 1)),所以尽量要选高位不同的两个数,从高位到低位逐位比较。
为了方便逐位比较,需要把每个非负整数展开成0/1序列,由此联想到字典树。关于字典树的详细介绍,可以参见:浅谈Trie树(字典树)。这里由于每一位只有0/1两种选择,因此字典树是二叉树。对于数组中的一个非负整数num,要求num与数组中元素异或的最大值,转化为在字典树中找到一条路径,使得高位的比特与num尽量不同。
由于题目规定了数组元素的范围,因此字典树的最大高度是31,是一个确定的常数,向字典树插入一个0/1序列和在字典树中查询一个最大异或路径这两个操作,都可以视为是O(1)时间复杂度的。因此建立字典树(向字典树中插入n个0/1序列)和找n个数的最大异或值,都是O(n)复杂度的,总的算法包含这两个步骤,自然也是O(n)复杂度的。
------------------------------------------------------------
代码
class Solution {
class TrieNode {
TrieNode left, right;
}
public int findMaximumXOR(int[] nums) {
TrieNode root = new TrieNode(), ptr = root;
// build trie tree
for (int num: nums) {
ptr = root;
for (int i = 30; i >= 0; --i) {
if ((num & (1 << i)) != 0) {
if (ptr.right == null) {
ptr.right = new TrieNode();
}
ptr = ptr.right;
} else {
if (ptr.left == null) {
ptr.left = new TrieNode();
}
ptr = ptr.left;
}
}
}
// find max xor for each num
int cur = 0, ans = 0;
for (int num: nums) {
ptr = root;
cur = 0;
for (int i = 30; i >= 0; --i) {
if ((num & (1 << i)) != 0) {
if (ptr.left != null)
{
cur += (1 << i);
ptr = ptr.left;
} else {
ptr = ptr.right;
}
} else {
if (ptr.right != null) {
cur += (1 << i);
ptr = ptr.right;
} else {
ptr = ptr.left;
}
}
}
ans = cur > ans? cur: ans;
}
return ans;
}
}