数组异或操作
这道题出自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
这题其实利用到了一个数学公式,即:
4
i
⊕
(
4
i
+
1
)
⊕
(
4
i
+
2
)
⊕
(
4
i
+
3
)
=
0
4i \oplus (4i + 1) \oplus (4i + 2) \oplus (4i + 3) = 0
4i⊕(4i+1)⊕(4i+2)⊕(4i+3)=0
这个公式的推导也很简单,首先4i用二进制肯定可以表示为:
4
i
=
(
x
x
x
x
x
00
)
2
4i = (xxxxx00)_2
4i=(xxxxx00)2
类似地,其他3个数有:
4
i
+
1
=
(
x
x
x
x
x
01
)
2
4i + 1 = (xxxxx01)_2
4i+1=(xxxxx01)2
4 i + 2 = ( x x x x x 10 ) 2 4i + 2 = (xxxxx10)_2 4i+2=(xxxxx10)2
4 i + 3 = ( x x x x x 11 ) 2 4i + 3 = (xxxxx11)_2 4i+3=(xxxxx11)2
显然这4个数用二进制表示的位数是相同的,这里假设为n,那么前n-2位的表示也是完全相同的,因此4个数前n-2位异或之后的结果为0,而后两位分别为00,01,10,11,异或之后的结果也为0,所以最终得到的结果是0。
再回到题目,就是求:
s
⊕
(
s
+
2
)
⊕
.
.
.
⊕
(
s
+
2
(
n
−
1
)
)
s \oplus (s + 2) \oplus ... \oplus (s + 2(n - 1))
s⊕(s+2)⊕...⊕(s+2(n−1))
如果s为偶数,则可以直接提取2出来,得到:
2
(
s
2
⊕
(
s
2
+
1
)
⊕
.
.
.
⊕
(
s
2
+
n
−
1
)
)
2(\frac{s}{2} \oplus (\frac{s}{2} + 1) \oplus ... \oplus (\frac{s}{2} + n - 1))
2(2s⊕(2s+1)⊕...⊕(2s+n−1))
如果s为奇数,则s,s + 2,…,s + 2(n - 1)都为奇数,可以表示为2i+1的形式。此时,我们注意到,异或结果的最后一位只取决于n的奇偶性,即n个1的异或值,如果n是奇数,那么最后一位就是1,反之如果n是偶数,则最后一位是0:
2
(
⌊
s
2
⌋
⊕
(
⌊
s
2
⌋
+
1
)
⊕
.
.
.
⊕
(
⌊
s
2
⌋
+
n
−
1
)
)
+
1
⊕
.
.
.
⊕
1
⏟
n
2(\lfloor\frac{s}{2}\rfloor \oplus (\lfloor\frac{s}{2}\rfloor + 1) \oplus ... \oplus (\lfloor\frac{s}{2}\rfloor + n - 1)) + \underbrace{1\oplus...\oplus1}_{n}
2(⌊2s⌋⊕(⌊2s⌋+1)⊕...⊕(⌊2s⌋+n−1))+n
1⊕...⊕1
那么实际上,我们可以把s为奇数和偶数得到的最终结果统一起来:
{
2
(
⌊
s
2
⌋
⊕
(
⌊
s
2
⌋
+
1
)
⊕
.
.
.
⊕
(
⌊
s
2
⌋
+
n
−
1
)
)
+
1
s
和
n
均
为
奇
数
2
(
⌊
s
2
⌋
⊕
(
⌊
s
2
⌋
+
1
)
⊕
.
.
.
⊕
(
⌊
s
2
⌋
+
n
−
1
)
)
s
和
n
不
均
为
奇
数
\begin{cases} 2(\lfloor\frac{s}{2}\rfloor \oplus (\lfloor\frac{s}{2}\rfloor + 1) \oplus ... \oplus (\lfloor\frac{s}{2}\rfloor + n - 1)) + 1 & s和n均为奇数 \\ 2(\lfloor\frac{s}{2}\rfloor \oplus (\lfloor\frac{s}{2}\rfloor + 1) \oplus ... \oplus (\lfloor\frac{s}{2}\rfloor + n - 1)) & s和n不均为奇数 \end{cases}
{2(⌊2s⌋⊕(⌊2s⌋+1)⊕...⊕(⌊2s⌋+n−1))+12(⌊2s⌋⊕(⌊2s⌋+1)⊕...⊕(⌊2s⌋+n−1))s和n均为奇数s和n不均为奇数
我们令f(k)为从0异或到k的结果,则上面的式子可以化简为:
{
2
(
f
(
⌊
s
2
⌋
+
n
−
1
)
⊕
f
(
⌊
s
2
⌋
−
1
)
)
+
1
s
和
n
均
为
奇
数
2
(
f
(
⌊
s
2
⌋
+
n
−
1
)
⊕
f
(
⌊
s
2
⌋
−
1
)
)
s
和
n
不
均
为
奇
数
\begin{cases} 2(f(\lfloor\frac{s}{2}\rfloor + n - 1) \oplus f(\lfloor\frac{s}{2}\rfloor - 1)) + 1 & s和n均为奇数 \\ 2(f(\lfloor\frac{s}{2}\rfloor + n - 1) \oplus f(\lfloor\frac{s}{2}\rfloor - 1)) & s和n不均为奇数 \end{cases}
{2(f(⌊2s⌋+n−1)⊕f(⌊2s⌋−1))+12(f(⌊2s⌋+n−1)⊕f(⌊2s⌋−1))s和n均为奇数s和n不均为奇数
现在,我们只需计算出f(k)即可。计算f(k)这时就用到前面提到的公式了,可以假设k = 4i, 4i + 1,4i + 2,4i + 3分别算出结果:
{ k k = 4 i 1 k = 4 i + 1 k + 1 k = 4 i + 2 0 k = 4 i + 3 \begin{cases}k & k = 4i \\ 1 & k = 4i + 1 \\ k + 1 & k = 4i + 2 \\ 0 & k = 4i + 3 \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧k1k+10k=4ik=4i+1k=4i+2k=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;
}
};