leetcode
leetcode 1601 ~ 1650
每个查询的最大异或值

每个查询的最大异或值

难度:

标签:

题目描述

代码结果

运行时间: 61 ms, 内存: 31.2 MB


/*
 * 题目思路:
 * 1. 对于每次查询,我们需要找到一个 k,使得 (nums 中所有元素 XOR k) 的值最大化。
 * 2. k 的范围是 0 到 2^maximumBit - 1。
 * 3. 要使 XOR 结果最大,我们需要尽可能设置 k 的二进制位为 1。
 * 4. 我们可以通过计算当前数组的 XOR 总和 prefixXOR,然后 k 可以通过 (2^maximumBit - 1) ^ prefixXOR 得到。
 * 5. 使用 Java Stream 的方式实现。
 */

import java.util.stream.IntStream;

public class Solution {
    public int[] getMaximumXor(int[] nums, int maximumBit) {
        int n = nums.length;
        int maxNum = (1 << maximumBit) - 1; // 2^maximumBit - 1
        int prefixXOR = IntStream.of(nums).reduce(0, (a, b) -> a ^ b);
        int[] answer = new int[n];

        IntStream.range(0, n).forEach(i -> {
            answer[i] = maxNum ^ prefixXOR;
            prefixXOR ^= nums[n - 1 - i];
        });

        return answer;
    }
}

解释

方法:

这个题解使用了前缀异或和的思路,从而避免了对数组进行实际的元素删除操作。首先,通过遍历整个数组,计算从第一个元素到当前元素的所有异或和,并存储到变量 x_or 中。利用异或操作的性质,x_or 可以在常数时间内通过上一个 x_or 值和当前元素进行更新。然后为了找到每一步的最大值,我们需要找到一个 k 值,使得 x_or XOR k 的结果最大。为了达到这一点,我们可以将 x_or 与 (1 << maximumBit) - 1 进行异或操作,该值实际上是在 maximumBit 位都为1的最大数字,这样可以确保异或结果的最大化。结果数组在完成遍历后需要反转,以匹配题目中逐步删除元素的顺序。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在计算最大异或结果时,使用 `x_or ^ max_num` 能保证得到最大值?
异或操作的一个关键性质是,两个不同位的异或结果为1。因此,为了使 `x_or ^ k` 的结果尽可能大,我们希望 `k` 中的每一位都能最大化 `x_or` 对应位的异或结果。如果 `x_or` 的某一位是0,那么 `k` 的对应位为1时,异或结果才为1,反之亦然。因此,`k` 的选择应使其与 `x_or` 的每一位尽可能不同。`max_num`,即 `(1 << maximumBit) - 1`,是一个所有有效位皆为1的数字,这确保了在有效位内 `k` 可以选择任何值来最大化与 `x_or` 的异或结果。
🦆
在这个算法中,`max_num` 的计算方法 `(1 << maximumBit) - 1` 是基于什么原理?为什么它能够覆盖所有小于 `2^maximumBit` 的 k 值?
`max_num` 的计算方法 `(1 << maximumBit) - 1` 制造了一个位数为 `maximumBit` 的二进制数,其中所有位都是1。这是因为 `1 << maximumBit` 产生了一个在第 `maximumBit` 位是1其余都是0的数,然后减1后,从第0位到第 `maximumBit-1` 位全变为1。这样的数是 `maximumBit` 位可以表示的最大数字,因此它确保了 `k` 的值可以取到任何小于 `2^maximumBit` 的数字,覆盖了所有可能的情况。
🦆
为什么最终结果数组 `ans` 需要进行反转操作?这与逐步删除数组元素的操作有什么直接关系?
在题解的过程中,数组 `ans` 从头到尾记录了对应每个前缀数组的最大异或值。但题目要求是在每次操作中删除数组的最后一个元素,然后求剩余数组的最大异或值。这意味着数组的最后一个元素对应的最大异或值应该首先被计算,随着元素逐个被删除,前缀异或和的计算顺序与题目要求的删除顺序相反。因此,为了符合题目的要求,需要将 `ans` 数组进行反转,使得每一步的计算结果符合逐步删除数组元素的顺序。

相关问题