题目描述
给你两个整数,n 和 start 。数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。
请返回 nums 中所有元素按位异或(XOR)后得到的结果。
示例 1:
输入:n = 5, start = 0
输出:8
解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。 “^” 为按位异或 XOR 运算符。
示例 2:
输入:n = 4, start = 3
输出:8
解释:数组 nums 为 [3, 5, 7, 9],其中 (3 ^ 5 ^ 7 ^ 9) = 8.
链接:https://leetcode-cn.com/problems/xor-operation-in-an-array
最简单的做法:直接模拟即可
这么简单就完事儿了,确实,但是并没有得到本题目的精髓
异或的性质: 4i ^ (4i+1) ^ (4i+2) ^ (4i+3) = 0
要计算的是:start ^ (start + 2i)^ (start + 4i ) ^ ……^(start+2(n-1))
这些数的奇偶性质相同,因此它们的二进制表示中的最低位或者均为 1,或者均为 0。于是我们可以把参与运算的数的二进制位的最低位提取出来单独处理。当且仅当 start 为奇数,且 n 也为奇数时,结果的二进制位的最低位才为 1。
具体可以参考官网题解:题解 需要注意的几点为:
-
(s⊕(s+1)⊕(s+2)⊕⋯⊕(s+n−1))×2+e,其中s=start/2。e表示运算结果的最低位。即我们单独处理最低位,而舍去最低位后的数列恰成为一串连续的整数。 为什么要单独把 e 拎出来?题目中说是为了形成一串连续的整数。参与异或运算的要不是偶数要不是奇数,为了转化成连续的整数需要为每个数除以2得到连续的数列,但是除以2是进行的是下取整,有些数字比如奇数除以2除不尽,舍掉的那部分怎么办?从余数中来获得。
-
(sumXor(s−1)⊕sumXor(s+n−1))*2+e。其中 乘以2 表示 左移一位,为什么前面要sumXor(s−1)?是因为计算的时候 是从 s 开始的,而sumXor(x) 表示从 0 到 x 的异或结果,因此需要使用异或运算的 x^x =0 0 ^ x =x 这两条性质,将前面无用的部分消掉。
-
代码最后是 return ret << 1 | e; 为什么要取 | 运算,因为求解出来的e 表示最终结果末尾位置为1,需要把这一 1 合并到最终结果中,与运算就不适合这样的,两个1相 与 才为1,这一末尾位置的结果就不对了。
-
这样计算复杂度为O(1) ,即使给定的 n 很大,也能很快求解
class Solution {
public:
int sumXor(int x) {
if (x % 4 == 0) {
return x;
}
if (x % 4 == 1) {
return 1;
}
if (x % 4 == 2) {
return x + 1;
}
return 0;
}
int xorOperation(int n, int start) {
int s = start >> 1, e = n & start & 1;
int ret = sumXor(s - 1) ^ sumXor(s + n - 1);
return ret << 1 | e;
}
};
链接:https://leetcode-cn.com/problems/xor-operation-in-an-array/solution/shu-zu-yi-huo-cao-zuo-by-leetcode-solution/