异或
异或是一种基于二进制的位运算,XOR或者^表示,它的运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。可以理解为不进位的加法。1+1=0, 0+0=0, 1+0=1
异或的性质
- 交换律:a XOR b = b XOR a;
- 结合律:a XOR b XOR c = a XOR ( b XOR c )
- 对于任何数x:都有x^x = 0, x ^ 0 = x;
- 自反性:a ^ b ^ b = a ^ 0 = a
异或的应用
- 交换两个元素的值
int a = 1, b = 2;
a = a ^ b;
b = b ^ a;
a = a ^ b;
- 找出多余的一个数字
数字1-n放入容量为n+1的数组arr中,只有唯一一个数重复,找出该重复的数
step1:对1-n进行异或得T1,对arr中所有元素进行异或得T2
step2: 重复的数为T1^T2
子数组亦或查询
题目出处:https://leetcode-cn.com/problems/xor-queries-of-a-subarray/
方法一:暴力(超时)
class Solution {
public:
vector<int> xorQueries(vector<int>& arr, vector<vector<int>>& queries) {
int n = queries.size();
int index = 0;
vector<int> ans(n);
for(auto & query : queries){
int l = query[0];
int r = query[1];
int res = arr[l];
for(int i = l+1; i <= r; ++i){
res ^= arr[i];
}
ans[index++] = res;
}
return ans;
}
};
方法二:前缀和
class Solution {
public:
vector<int> xorQueries(vector<int>& arr, vector<vector<int>>& queries) {
int n = arr.size();
vector<int> nSum(n+1, 0);
for(int i = 1; i <= n; ++i){ //求前缀亦或值
nSum[i] = nSum[i-1]^arr[i-1];
}
int index = 0;
vector<int> ans(queries.size());
for(auto & query : queries){
int l = query[0];
int r = query[1];
ans[index++] = nSum[l]^nSum[r+1]; //l+1到r+1的异或值
}
return ans;
}
};
解码异或后的排列
题目出处:https://leetcode-cn.com/problems/decode-xored-permutation/
思路:若得到原数组的第一个元素,就可解码数组。数组的第一个元素可以由前n个正整数的异或和除了数组第一个元素外的所有元素的异或得到。
class Solution {
public:
vector<int> decode(vector<int>& encoded) {
int n = encoded.size() + 1;
int total = 0;
for (int i = 1; i <= n; i++) {
total ^= i;
}
int odd = 0;
for (int i = 1; i < n - 1; i += 2) {
odd ^= encoded[i];
}
vector<int> perm(n);
perm[0] = total ^ odd;
for (int i = 0; i < n - 1; i++) {
perm[i + 1] = perm[i] ^ encoded[i];
}
return perm;
}
};