1.题目描述
有一个正整数数组 arr,现给你一个对应的查询数组 queries,其中 queries[i] = [Li, Ri]。
对于每个查询 i,请你计算从 Li 到 Ri 的 XOR 值(即 arr[Li] xor arr[Li+1] xor ... xor arr[Ri])作为本次查询的结果。
并返回一个包含给定查询 queries 所有结果的数组。
示例 1:
输入: arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]]
输出: [2,7,14,8]
解释:
数组中元素的二进制表示形式是:
1 = 0001
3 = 0011
4 = 0100
8 = 1000
查询的 XOR 值为:
[0,1] = 1 xor 3 = 2
[1,2] = 3 xor 4 = 7
[0,3] = 1 xor 3 xor 4 xor 8 = 14
[3,3] = 8
示例 2:
输入: arr = [4,8,2,10], queries = [[2,3],[1,3],[0,0],[0,3]]
输出: [8,0,4,4]
2.解题思路
利用异或的数学性质实现前缀异或
异或有三个核心性质(是优化的关键):
- 交换律 / 结合律:
a^b^c = a^(b^c) = (a^b)^c; - 自反性:
a^a = 0(相同数异或结果为 0); - 零元:
a^0 = a(任何数和 0 异或结果不变)。
基于这些性质,我们构建前缀异或数组:
- 定义
prefix[0] = 0; prefix[i] = arr[0] ^ arr[1] ^ ... ^ arr[i-1](prefix[i]表示前i个元素的异或和);- 对于查询
[l, r],区间异或结果 =prefix[l] ^ prefix[r+1](推导:prefix[r+1] = prefix[l] ^ (arr[l]^...^arr[r]),两边异或prefix[l]即可得到区间结果)。
3. 具体步骤
- 构建前缀异或数组
prefix; - 遍历每个查询,用
prefix[l] ^ prefix[r+1]计算结果; - 汇总所有查询结果并返回。
3.代码实现
class Solution {
public:
vector<int> xorQueries(vector<int>& arr, vector<vector<int>>& queries) {
// 1. 构建前缀异或数组(长度为arr.size()+1,prefix[0]=0)
int n = arr.size();
vector<int> prefix(n + 1, 0);
for (int i = 1; i <= n; ++i) {
prefix[i] = prefix[i - 1] ^ arr[i - 1];
}
// 2. 处理每个查询,计算区间异或结果
vector<int> res;
for (auto& q : queries) {
int l = q[0];
int r = q[1];
// 核心公式:区间[l,r]的异或和 = prefix[l] ^ prefix[r+1]
int xor_val = prefix[l] ^ prefix[r + 1];
res.push_back(xor_val);
}
return res;
}
};