简介
题目链接 LeetCode 1829. Maximum XOR for Each Query
本题的标签是Bit Manipulation
,典型的位运算题目。
注意:文章中一切注解皆为Python代码
理解题目
题目非常简单。给定一个已排序的数列nums
,和一个最大二进制位值maximumBit
。数列中的每一个数字都小于2maximumBit,也就是他们的二进制表示最多只有maximumBit
位。
举个例子,如果maximumBit = 3
,那么数列可以包含的最大值就是7
,因为7
的二进制是111
,也就是只有maximumBit = 3
位;相比之下8
的二进制表示是1000
,也就是4位,就不满足条件。
题目说要有n
次查询,每一次查询要求
- 找出一个小于 2maximumBit 的
k
值使得nums[0] XOR nums[1] XOR ... XOR nums[nums.length-1] XOR k
最大 - 同时,每一次查询之后要把
nums
中最后一个数字弹pop
出来
题目剖析+思考过程
如果对位运算不够了解的话,看完题目可能有点懵,懵在到底如何找出使上述条件最大的K
呢?
在没有任何位运算知识的前提下,求得解可能就是一个暴力的枚举算法,尝试每一个从1到2maximumBit 之间的k
值,然后保留使得条件最大的相应k
值。
但是结合一些位运算知识,尤其是(异或xor
),我们可以推出一个结论,一起来看一下:
- 异或运算是不能增加位数的,举个例子:
1 == 0b001
,二进制表达式有三位数6 == 0b110
,二进制表达式有三位数1 ^ 6 == 7 == 0b111
,依旧只有三位
- 也就是说,如果 x < 2maximumBit, 且 y < 2maximumBit , 那么 x ^ y < 2maximumBit
题目和题目最下面的条件限制分别提到:
- k < 2maximumBit
- 0 <= nums[i] < 2maximumBit
根据所有这些知识,我们就知道不论找出什么样的数字,无论大小,数量,只要是在[0, 2maximumBit ]这个范围内,异或出来的最大结果也只能是2maximumBit -1。
既然现在我们知道最大值了,那通过结果找因数就很容易了,就是一个简单的异或操作,这里用到了异或的另一个特性:
- 如果
x ^ y == z
,那么x ^ z == y
,同时y ^ z == x
既然我们知道了nums[0] XOR nums[1] XOR ... XOR nums[nums.length-1] XOR k == (2^maximumBit-1)
,那么k == nums[0] XOR nums[1] XOR ... XOR nums[nums.length-1] XOR (2^maximumBit-1)
。
代码实现(附注释)
class Solution:
def getMaximumXor(self, nums: List[int], maximumBit: int) -> List[int]:
pre_xor = 0
for num in nums: pre_xor ^= num # 求所有数字异或之后的结果
maxnum = 2 ** maximumBit - 1 # 最大值
results = []
while nums:
results.append(pre_xor ^ maxnum) # 通过结果,用异或反推K值
pre_xor ^= nums.pop() # 按题目要求,每轮弹出最后一个值
return results
解题后的思考
可以说这是一道有点Tricky的题,理论上面没有什么难度,主要考察对题目输入范围的理解,和异或的熟悉程度,以及衍生的思考。
总结一下,异或的几个知识点:
- 如果
x ^ y == z
,那么x ^ z == y
,同时y ^ z == x
- 显然
x ^ 0 == x
,可以得出推论x ^ x == 0
- 异或不能增加二进制表示下的最大位数。因次,知道二进制位数的上限也就是知道了异或结果的上限。