题目
题目来源:力扣(LeetCode)
给定一个整数数组 nums ,返回 nums[i] XOR nums[j] 的最大运算结果,其中 0 ≤ i ≤ j < n 。
 
示例 1:
输入:nums = [3,10,5,25,2,8]
输出:28
解释:最大运算结果是 5 XOR 25 = 28.
示例 2:
输入:nums = [0]
输出:0
示例 3:
输入:nums = [2,4]
输出:6
示例 4:
输入:nums = [8,10,2]
输出:10
示例 5:
输入:nums = [14,70,53,83,49,91,36,80,92,51,66,70]
输出:127
思路分析
- 在一个数组中求两个数的异或最大值,需要考虑以下两点:
- 大的数异或后带来的增益较大,所以优先考虑大的数进行异或,也就是先考虑高位。
 - 只有当两个二进制位不同,二进制位才会为1,所以,我们尽量找到两个很多位都不同的数进行异或。
 
 - 构建前缀树:将所有的数都插入前缀树中。与普通前缀树不同,这里是根据一个数的二进制位来插入,普通前缀树是根据单词中的字符来插入。还有一点需要注意的是,我们优先考虑高位,所以是从高位到低位进行插入
 - 对于 nums 中的每个数 num ,都到前缀树中去搜索num最大异或的那个数,然后计算最大异或值,最后,从这些异或值中挑出最大的一个就是要的答案。
 
/*** @param {number[]} nums* @return {number}*/var findMaximumXOR = function (nums) {// 前缀树 先将每一个树的31位二进制位存入到前缀树中let root = {};for (let num of nums) {let cur = root;let bit = 0; // 减少空间for (let i = 30; i >= 0; i--) { // JS是31位数,所以右移30位// 数据是从高位开始存储(后面高位亦或取1,结果肯定是最大的)bit = (num >> i) & 1;if (!cur[bit]) cur[bit] = {};cur = cur[bit];}}// 时间复杂度 O(N) 因为每个数据在前缀树中查找一次就能得到它与其他数xor的最大结果// 此处准确时间复杂度应该是 O(31N)let ans = 0;for (let num of nums) {let cur = root;let res = 0;for (let i = 30; i >= 0; i--) {let bit = (num >> i) & 1;if (cur[1] && (1 ^ bit == 1)) {res = (res << 1) + 1; // 有1取1cur = cur[1];} else if (cur[0] && (0 ^ bit == 1)) {res = (res << 1) + 1; // 有1取1cur = cur[0];} else { // else 说明不是两个都有的,取一个有的就行res = res << 1;cur = cur[bit];}}// 每次计算二进制算一次值if (res > ans) ans = res;}return ans;};
