|
| 1 | +# 题目地址(5640. 与数组中元素的最大异或值) |
| 2 | + |
| 3 | +https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/ |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +``` |
| 8 | +给你一个由非负整数组成的数组 nums 。另有一个查询数组 queries ,其中 queries[i] = [xi, mi] 。 |
| 9 | +
|
| 10 | +第 i 个查询的答案是 xi 和任何 nums 数组中不超过 mi 的元素按位异或(XOR)得到的最大值。换句话说,答案是 max(nums[j] XOR xi) ,其中所有 j 均满足 nums[j] <= mi 。如果 nums 中的所有元素都大于 mi,最终答案就是 -1 。 |
| 11 | +
|
| 12 | +返回一个整数数组 answer 作为查询的答案,其中 answer.length == queries.length 且 answer[i] 是第 i 个查询的答案。 |
| 13 | +
|
| 14 | + |
| 15 | +
|
| 16 | +示例 1: |
| 17 | +
|
| 18 | +输入:nums = [0,1,2,3,4], queries = [[3,1],[1,3],[5,6]] |
| 19 | +输出:[3,3,7] |
| 20 | +解释: |
| 21 | +1) 0 和 1 是仅有的两个不超过 1 的整数。0 XOR 3 = 3 而 1 XOR 3 = 2 。二者中的更大值是 3 。 |
| 22 | +2) 1 XOR 2 = 3. |
| 23 | +3) 5 XOR 2 = 7. |
| 24 | +示例 2: |
| 25 | +
|
| 26 | +输入:nums = [5,2,4,6,6,3], queries = [[12,4],[8,1],[6,3]] |
| 27 | +输出:[15,-1,5] |
| 28 | + |
| 29 | +
|
| 30 | +提示: |
| 31 | +
|
| 32 | +1 <= nums.length, queries.length <= 105 |
| 33 | +queries[i].length == 2 |
| 34 | +0 <= nums[j], xi, mi <= 109 |
| 35 | +
|
| 36 | +``` |
| 37 | + |
| 38 | +## 前置知识 |
| 39 | + |
| 40 | +- 异或 |
| 41 | +- 位运算 |
| 42 | +- 剪枝 |
| 43 | +- 双指针 |
| 44 | + |
| 45 | +## 公司 |
| 46 | + |
| 47 | +- 暂无 |
| 48 | + |
| 49 | +## 思路 |
| 50 | + |
| 51 | +PS:使用 JS 可以平方复杂度直接莽过。不过这个数据范围平方意味着 $10^(10)$ 次运算,很难想象这是怎么 AC 的。 |
| 52 | + |
| 53 | +使用前缀树的思路和 [字节跳动的算法面试题是什么难度?(第二弹)](https://lucifer.ren/blog/2020/09/06/byte-dance-algo-ex-2017/) 第二题比较像,很多人的解法也是如此,我就不贴了。如果还是不懂得同学,建议先看下 [421. 数组中两个数的最大异或值](https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/),基本就是一个前缀树的模板。 |
| 54 | + |
| 55 | +下面介绍一个 预处理 + 双指针的方法。 |
| 56 | + |
| 57 | +和 [421. 数组中两个数的最大异或值](https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/) 类似,核心一句话要记住。 |
| 58 | + |
| 59 | +不要关心 x 最后和 nums 中的谁异或了,**只关心最终异或的数的每一位分别是多少**。 |
| 60 | + |
| 61 | +以 nums[0,1,2,3,4], x 为 9 为例,给大家讲解一下核心原理。 |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | +具体算法: |
| 68 | + |
| 69 | +- 首先对数据进行预处理,建立一个二维 dp 数组, dp[i][j] 是和 nums[j] 第 i 位相等的最小的数组下标。 |
| 70 | +- 为了使用双指针,我们需要对 nums 进行排序 |
| 71 | +- 接下来对每一个查询,我们调用 solve 函数计算最大的异或值。 |
| 72 | +- solve 函数内部使用双指针,比较头尾指针和 x 的异或结果。更新异或结果较小的那个即可。 |
| 73 | + |
| 74 | +## 代码 |
| 75 | + |
| 76 | +```py |
| 77 | +class Solution: |
| 78 | + def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]: |
| 79 | + def solve(x, m, s, e): |
| 80 | + if nums[0] > m: return -1 |
| 81 | + max_v = 0 |
| 82 | + for i in range(31, -1, -1): |
| 83 | + if nums[s] & (1<<i) == nums[e] & (1<<i): |
| 84 | + max_v += nums[s] & (1<<i) |
| 85 | + elif nums[dp[i][e]] <= m and x ^ nums[s] < x ^ nums[e]: |
| 86 | + max_v += nums[e] & (1<<i) |
| 87 | + # 直接移动较小指针(s)到 dp[i][e],其他不可能是答案 |
| 88 | + s = dp[i][e] |
| 89 | + else: |
| 90 | + max_v += nums[s] & (1<<i) |
| 91 | + # 直接移动较小指针(e)到 dp[i][e] - 1,其他不可能是答案 |
| 92 | + e = dp[i][e] - 1 |
| 93 | + |
| 94 | + return max_v ^ x |
| 95 | + |
| 96 | + nums.sort() |
| 97 | + n = len(nums) |
| 98 | + # dp[i][j] 是和 nums[j] 第 i 位相等的最小的数组下标 |
| 99 | + dp = [[0 for _ in range(n)] for _ in range(32)] |
| 100 | + for i in range(32): |
| 101 | + for j in range(n): |
| 102 | + if j == 0 or (nums[j] & (1<<i)) != (nums[j-1] & (1<<i)): dp[i][j] = j |
| 103 | + else: dp[i][j] = dp[i][j-1] |
| 104 | + return [solve(x, m, 0, n-1) for x,m in queries] |
| 105 | +``` |
| 106 | + |
| 107 | +**复杂度分析** |
| 108 | + |
| 109 | +- 时间复杂度:$O(max(NlogN, 32*Q))$,其中 Q 为 queries 长度,N 为 nums 长度。 |
| 110 | +- 空间复杂度:$O(32*N)$,其中 N 为 nums 长度。 |
0 commit comments