Hi 你們好,我是張小豬。歡迎來到『寶寶也能看懂』系列特別篇 - 30-Day LeetCoding Challengegit
這是一個 leetcode 官方的小活動,地址在這裏(若是被重定向回中文站了,去掉域名裏的 -cn
便可)。活動內容很簡單,從 4 月 1 號開始,天天會選出一道題(國內時間中午 12 點更新),在 24 小時內完成便可得到一點小獎勵。雖然獎勵彷佛也沒什麼用,不過做爲一個官方的打卡活動,小豬仍是來打一下卡吧,正好做爲天天下班回家後的娛樂。github
這裏是 4 月 1 號的題,也是題目列表中的第 136 題 -- 『只出現一次的數字』算法
給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。shell
說明:segmentfault
你的算法應該具備線性時間複雜度。 你能夠不使用額外空間來實現嗎?數組
示例 1:數據結構
輸入: [2,2,1] 輸出: 1
示例 2:spa
輸入: [4,1,2,1,2] 輸出: 4
EASYcode
這道題彷佛沒什麼好講的,大概是做爲活動的開篇,預熱一下,吸引圍觀,激勵用戶參與。blog
下面給出幾個方案,供小夥伴們參考。
其實這是個湊數的方案(哈哈哈,沒想到吧)。小豬相信不會有小夥伴們這麼去寫的,畢竟直接就到 O(n^2) 了,實在是太浪費了。權且做爲最最基礎的實現吧。
const singleNumber = nums => { const arr = []; for (const n of nums) { const idx = arr.indexOf(n); idx === -1 ? arr.push(n) : arr.splice(idx, 1); } return arr.pop(); };
用 Set
代替了方案 1 中的數組,使得查詢和刪除都快了不少。不過代碼仍是太多了,而且也得基於額外的數據結構和空間,並不推薦。
const singleNumber = nums => { const set = new Set(); for (const n of nums) { set.has(n) ? set.delete(n) : set.add(n); } for (const x of set.keys()) return x; };
用位操做代替了前兩種方案裏對於額外數據結構和空間的依賴。小豬以爲這個方案算是這道題的標準實現吧,纔不會告訴你前兩種方案是爲了寫文章才湊出來的呢 hia hia hia O(∩_∩)O
稍微解釋一下異或這個位操做吧,它的行爲邏輯能夠理解爲兩個值不一樣則爲 true
,相同則爲 false
。以下表:
0 ^ 0 === 0 0 ^ 1 === 1 1 ^ 0 === 1 1 ^ 1 === 0
那麼基於這個運算邏輯,咱們能夠發現,對於兩個相同的數值進行異或運算,那麼結果必定是 0。再看看咱們題目中的數據,正好是成對的數字加上一個單獨的數字。這時候再加上異或這個運算能夠知足交換律和結合律,因而咱們那些成對的數字運算完後正好爲 0,而 0 與一個數字進行異或預算即是這個數字自己。
基於這個思路,咱們能夠獲得以下的代碼:
const singleNumber = nums => { let ret = 0; for (const n of nums) ret ^= n; return ret; };
固然,都寫成這樣了,不如咱們就直接一行吧:
const singleNumber = nums => nums.reduce((prev, cur) => prev ^ cur, 0);
關於異或操做的一些實際應用場景,這裏再補充幾個栗子吧。
let a = 10; let b = 20; a = a ^ b; b = b ^ a; a = b ^ a; console.log(a, b) // 20, 10
稍微解釋一下過程吧:
a
。b
中兩個數不一樣的位取反,相同的位保持不變,因而 b 就變成了 a,而後保存進變量 b
中。b
中兩個數不一樣的位取反,相同的位保持不變。注意,這時候的 b
中的值實際上是 a,因此運算後獲得的值是 b,而後保存進變量 a
裏。b
,b 就進了 a
。let a = 10; let b = 20; while (b !== 0) { const a2 = a ^ b; const b2 = (a & b) << 1; a = a2; b = b2; } console.log(a) // 30
同理,不過這裏面還用到了與操做和左移操做。原理其實和加法是同樣的,就是按位相加,而後須要進位的地方就進位。不過在二進制中,可能的狀況會比較少。具體以下:
這是 『30-Day LeetCoding Challenge』 的第一題,沒有太多能夠說的,因而就稍微拓展了一點關於異或操做的內容。但願能夠幫到有須要的小夥伴。
若是以爲不錯的話,記得『三連』哦。小豬愛大家喲~ >.<