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))求解,再按位與便可。