1486. 数组异或操做java
力扣官方题解L6算法
1486. 数组异或操做
难度简单83数组
给你两个整数,
n
和start
。函数数组
nums
定义为:nums[i] = start + 2*i
(下标从 0 开始)且n == nums.length
。code请返回
nums
中全部元素按位异或(XOR)后获得的结果。leetcode示例 1:get
输入: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:it
输入:n = 1, start = 7 输出:7示例 4:io
输入:n = 10, start = 5 输出:2提示:
1 <= n <= 1000
0 <= start <= 1000
n == nums.length
思路
按照题意模拟便可:
代码
class Solution { public int xorOperation(int n, int start) { int ans = 0; for (int i = 0; i < n; ++i) { ans ^= (start + i * 2); } return ans; } }
复杂度分析
记 ⊕ 为异或运算,异或运算知足如下性质:
在本题中,咱们须要计算 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 表示运算结果的最低位。即咱们单独处理最低位,而舍去最低位后的数列恰成为一串连续的整数。
这样咱们能够描述一个函数 sumXor(x),表示0⊕1⊕2⊕⋯⊕x。利用异或运算的性质 5,咱们能够将计算该函数的复杂度下降到 O(1),由于以 4i 为开头的连续四个整数异或的结果为 0,因此 sumXor(x) 能够被表示为:
$$ \text{sumXor}(x)= \begin{cases} x,& x=4k,k\in Z\\ (x-1) \oplus x,& x=4k+1,k\in Z\\ (x-2) \oplus (x-1) \oplus x,& x=4k+2,k\in Z\\ (x-3) \oplus (x-2) \oplus (x-1) \oplus x,& x=4k+3,k\in Z\\ \end{cases} $$
咱们能够进一步化简该式:
$$ \text{sumXor}(x)= \begin{cases} x,& x=4k,k\in Z\\ 1,& x=4k+1,k\in Z\\ x+1,& x=4k+2,k\in Z\\ 0,& x=4k+3,k\in Z\\ \end{cases} $$
这样最后的结果便可表示为:
$$ (\text{sumXor}(s-1) \oplus \text{sumXor}(s+n-1))\times 2 + e) $$
代码
class Solution { public 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; } 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; } }
复杂度分析
首先,下面的计算公式中前两项,运用了前缀和的思路,即
$$ \begin{cases} \text{sumXor}(s-1)\quad\quad\ = 0 \oplus 1 \oplus 2 \oplus ··· \oplus {(s-2)} \oplus {(s-1)}\\ \text{sumXor}(s+n-1)) = 0 \oplus 1 \oplus 2 \oplus ··· \oplus {(s-2)} \oplus {(s-1)} \oplus {(s)} \oplus {(s+1)} \oplus ···\oplus {(s+n-2)}\oplus {(s+n-1)} \end{cases} $$
故,按照性质1,这两项进行异或时,至关于作前缀和的减法,即:
$$ \text{sumXor}(s-1) \oplus \text{sumXor}(s+n-1) =[0 \oplus 1 \oplus ··· \oplus {(s-1)}] \oplus [0 \oplus 1 \oplus ··· \oplus {(s-1)} \oplus {s} \oplus ···\oplus {(s+n-2)}\oplus {(s+n-1)}] \\ \quad\quad \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad =[0 \oplus 0 \oplus 1 \oplus 1 \oplus ··· \oplus {(s-1)} \oplus {(s-1)}] \oplus {s} \oplus ···\oplus {(s+n-2)}\oplus {(s+n-1)} \\ \quad\quad \quad\quad \quad\quad \quad\quad \quad\quad \quad\quad \quad\quad = {s} \oplus {(s+1)} \oplus···\oplus {(s+n-2)}\oplus {(s+n-1)} $$
对于 e 计算,则是出于如下缘由点:
对于二进制数,由于每次都是给 start 加上 2 的倍数,因此,最后获得的数组中全部数字二进制的最后一位一直是不变的,即 start 若是是偶数,则数组中全部数都是偶数,最后一位全为0,若是是奇数,则数组中全部数都是奇数,最后一位全为1。
所以可知,只有 start为奇数,而且n为奇数时,e的最后一位才能为1,其余状况全为0。
又由于咱们只须要最后一位,因此还要按位与上1,即:n & start & 1
综合思考1
和思考2
,咱们能够把题目作以推广,即:
给你三个整数,
n
、start
和k
。数组
nums
定义为:nums[i] = start + k*i
(i从0开始,k=2^m(m>=1))且n == nums.length
。请返回
nums
中全部元素按位异或(XOR)后获得的结果。
题目的解法和上面的同样,结果 result 能够表示为:
$$ result =\text{sumXor}(s-1) \oplus \text{sumXor}(s+n-1))\times k + e \\ 其中 s=\lfloor \frac{\textit{start}}{2} \rfloor,e=(start \% k) \oplus (start \% k) \oplus ···\oplus(start \% k)\oplus(start \% k) $$
而上面的e等于n个start对k的余数异或,可参照思考2
,分别对倒数第一位,倒数第二位,一直到倒数第m位(k=2^m(m>=1))求解,再按位与便可。