数组异或操作
这道题出自LeetCode,题目如下:
给你两个整数,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.
示例 3:
输入:n = 1, start = 7
输出:7
示例 4:
输入:n = 10, start = 5
输出:2
这题其实利用到了一个数学公式,即:
这个公式的推导也很简单,首先4i用二进制肯定可以表示为:
类似地,其他3个数有:
显然这4个数用二进制表示的位数是相同的,这里假设为n,那么前n-2位的表示也是完全相同的,因此4个数前n-2位异或之后的结果为0,而后两位分别为00,01,10,11,异或之后的结果也为0,所以最终得到的结果是0。
再回到题目,就是求:
如果s为偶数,则可以直接提取2出来,得到:
如果s为奇数,则s,s + 2,...,s + 2(n - 1)都为奇数,可以表示为2i+1的形式。此时,我们注意到,异或结果的最后一位只取决于n的奇偶性,即n个1的异或值,如果n是奇数,那么最后一位就是1,反之如果n是偶数,则最后一位是0:
那么实际上,我们可以把s为奇数和偶数得到的最终结果统一起来:
我们令f(k)为从0异或到k的结果,则上面的式子可以化简为:
现在,我们只需计算出f(k)即可。计算f(k)这时就用到前面提到的公式了,可以假设k = 4i, 4i + 1,4i + 2,4i + 3分别算出结果:
通过的代码如下:
class Solution {
public:
int xorOperation(int n, int start) {
int t = start >> 1;
int res = helper(t - 1) ^ helper(t + n - 1);
return (res << 1) | ((start & 0x1) & (n & 0x1));
}
int helper(int t)
{
int res = 0;
switch(t & 0x3)
{
case 0:
res = t;
break;
case 1:
res = 1;
break;
case 2:
res = t + 1;
break;
case 3:
res = 0;
}
return res;
}
};