Medium
题目描述
给你一个由 n 个非负整数组成的数组 nums 和一个整数 maximumBit。你需要执行以下查询 n 次:
找到一个非负整数 k < 2^maximumBit,使得 nums[0] XOR nums[1] XOR … XOR nums[nums.length-1] XOR k 的结果最大。k 是第 i 次查询的答案。 从当前数组 nums 中移除最后一个元素。
返回数组 answer,其中 answer[i] 是第 i 次查询的答案。
示例 1:
输入:nums = [0,1,1,3], maximumBit = 2
输出:[0,3,2,3]
解释:查询的答案如下:
第 1 次查询:nums = [0,1,1,3], k = 0 因为 0 XOR 1 XOR 1 XOR 3 XOR 0 = 3。
第 2 次查询:nums = [0,1,1], k = 3 因为 0 XOR 1 XOR 1 XOR 3 = 3。
第 3 次查询:nums = [0,1], k = 2 因为 0 XOR 1 XOR 2 = 3。
第 4 次查询:nums = [0], k = 3 因为 0 XOR 3 = 3。
示例 2:
输入:nums = [2,3,4,7], maximumBit = 3
输出:[5,2,6,5]
示例 3:
输入:nums = [0,1,2,2,5,7], maximumBit = 3
输出:[4,3,6,4,6,7]
约束条件:
- nums.length == n
- 1 <= n <= 10^5
- 1 <= maximumBit <= 20
- 0 <= nums[i] < 2^maximumBit
- nums 按升序排列
解题思路
这道题的关键在于理解异或运算的性质和如何获得最大异或值。
核心思路:
最大异或值的目标:我们希望得到的最大异或结果是
2^maximumBit - 1,即所有 maximumBit 位都为 1 的数。异或性质利用:如果当前前缀的异或值为
prefix_xor,要使prefix_xor XOR k等于目标值max_val,则k = prefix_xor XOR max_val。前缀异或的计算:我们可以预先计算所有前缀的异或值,然后从后往前处理每个查询。
逆向思考:由于每次都要移除最后一个元素,我们可以从完整数组开始,逐步移除元素,这样避免重复计算前缀异或。
算法步骤:
- 计算整个数组的异或值
- 对于每次查询,当前的 k 值 = 当前异或值 XOR (2^maximumBit - 1)
- 移除最后一个元素(通过异或操作:当前异或值 XOR 最后元素)
时间复杂度为 O(n),空间复杂度为 O(1)(不考虑输出数组)。
代码实现
class Solution {
public:
vector<int> getMaximumXor(vector<int>& nums, int maximumBit) {
int n = nums.size();
int maxVal = (1 << maximumBit) - 1;
int xorAll = 0;
// 计算整个数组的异或值
for (int num : nums) {
xorAll ^= num;
}
vector<int> answer(n);
// 从后往前处理每个查询
for (int i = 0; i < n; i++) {
// 当前查询的答案
answer[i] = xorAll ^ maxVal;
// 移除最后一个元素
xorAll ^= nums[n - 1 - i];
}
return answer;
}
};
class Solution:
def getMaximumXor(self, nums: List[int], maximumBit: int) -> List[int]:
n = len(nums)
max_val = (1 << maximumBit) - 1
xor_all = 0
# 计算整个数组的异或值
for num in nums:
xor_all ^= num
answer = []
# 从后往前处理每个查询
for i in range(n):
# 当前查询的答案
answer.append(xor_all ^ max_val)
# 移除最后一个元素
xor_all ^= nums[n - 1 - i]
return answer
public class Solution {
public int[] GetMaximumXor(int[] nums, int maximumBit) {
int n = nums.Length;
int maxVal = (1 << maximumBit) - 1;
int xorAll = 0;
// 计算整个数组的异或值
foreach (int num in nums) {
xorAll ^= num;
}
int[] answer = new int[n];
// 从后往前处理每个查询
for (int i = 0; i < n; i++) {
// 当前查询的答案
answer[i] = xorAll ^ maxVal;
// 移除最后一个元素
xorAll ^= nums[n - 1 - i];
}
return answer;
}
}
var getMaximumXor = function(nums, maximumBit) {
const n = nums.length;
const maxVal = (1 << maximumBit) - 1;
let xorAll = 0;
// 计算整个数组的异或值
for (const num of nums) {
xorAll ^= num;
}
const answer = [];
// 从后往前处理每个查询
for (let i = 0; i < n; i++) {
// 当前查询的答案
answer.push(xorAll ^ maxVal);
// 移除最后一个元素
xorAll ^= nums[n - 1 - i];
}
return answer;
};
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) |
其中 n 为数组 nums 的长度。我们只需要遍历数组一次来计算初始异或值,然后再遍历一次来生成答案,因此时间复杂度为 O(n)。除了输出数组外,只使用了常数额外空间。