今天看到的第一眼,诶,竟然是个simple的,那应该会很简单的,然后一看题
我就傻眼了,异或操作……,两三年前上离散数学的时候学过,很久不用,早就已经忘了。那么先查一下,这个异或运算到底是怎么算的吧。
- 关于异或运算
- 异或运算最能讲明白的一句话就是“同为0,异为1”,即如果两个位次的数相等,那么这一位的结果就是0,如果这两个位次的数不等,那么这一位的结果就是1。
- 在C++编程语言里,它的运算符是“^”,那么异或运算的公式可以写成:a ^ b=(~a & b) | (a & ~b)
- 我们以“2^4”为例:
- “2”转化为2进制是“010”,“4”的二进制是“100”。
- 那么对于每一位进行异或运算,相同的是0,不同的为1
- 那么,最后的结果就是“110”,转化为十进制就是6
- 即 2^4=6
- 性质:
-
x^x=0;
-
交换率:x^y=y^x
-
结合率:(x^y)^z = x^(y^z)
-
自反性:x^y^y=x, x^x^y=y
-
对于i>=0,有 4i ^ (4i+1) ^ (4i+2) ^ (4i+3)=0
-
-
解题
-
比较直观的方法就是一个循环,在循环过程中对所有元素挨个进行异或运算,最后得到结果。时间复杂度是O(n),空间复杂度是O(1)。代码(C++)如下
class Solution { public: int xorOperation(int n, int start) { int res = start; for(int i=1;i<n;i++) { res = res^(start+2*i); } return res; } };
-
- 第二种方法则应用到了异或运算的性质5.
- 那么,对于数组nums中的所有元素,nums[i]=start+2*i,这些元素要么都是偶数,要么都是奇数,这是由start的初始值决定的。所以这些数转成二进制之后,最后一位的数值都相同,奇数就都是1,偶数则都是0。因为他们都相同,所以异或结果的最后一位必然是0。
- 将nums中的所有元素都下除以2(比如5/2=2),得到的值就是一个从start/2开始长度为n的连续数组。(比如对于实例二来说,得到的结果是 [1,2,3,4])
- 那么对于新的数组中元素来说,它们每个4*i到4*i+3的元素异或,得到的结果就是0,0异或任何一个数仍等于那个数,所以消去它们。故,对于有n个数组的元素来说,只需要计算前面m1个值异或后m2个值的结果(m1\m2均小于等于3)。
- 第3步得到的结果的二进制在后面再加个0,或者结果的十进制乘以2,得到的就是最终的结果。
(当然,在第3步计算的时候,直接用原始数据来计算,等价于先除2再乘2的结果,所以化简以后只是计算前面m1个值异或后m2个值的结果即可)