【LeetCodeAnimation】三道「只出現一次的數」一文輕鬆搞定!

點擊上方「五分鐘學算法」,選擇「星標」公衆號web

重磅乾貨,第一時間送達算法


今天咱們來作幾道很是經典的題目,第一道題目咱們會用多種方法解答,雖然這是一道簡單題目,可是咱們學會了這幾種解題方法,徹底能夠輕鬆應對後面兩道中等題目。廢話很少說,咱們來看題目吧。
數組

爲保證嚴謹性,文章中的全部代碼均通過測試,你們能夠放心食用
題目來源:leetcode 136只出現一次的數(簡單),137只出現一次的數Ⅱ(中等) 260只出現一次的數Ⅲ(中等)

只出現一次的數

給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。微信

示例 1:app

輸入: [2,2,1] 輸出: 1編輯器

示例 2:測試

輸入: [4,1,2,1,2] 輸出: 4flex

這個題目很是容易理解,就是讓咱們找出那個只出現一次的數字,那麼下面咱們來看一下這幾種解題方法吧url

HashMap

用 HashMap 的這個方法是很容易實現的,題目要求不是讓咱們求次數嘛,那咱們直接遍歷數組將每一個數字和其出現的次數存到哈希表裏就能夠了,而後咱們再從哈希表裏找出出現一次的那個數返回便可。spa


題目代碼

排序搜索法

這個方法也是特別容易想到的,咱們首先對數組進行排序,而後遍歷數組,由於數組中其餘數字都出現兩次,只有目標值出現一次,因此則讓咱們的指針每次跳兩步,當發現當前值和前一位不同的狀況時,返回前一位便可,固然咱們須要考慮這種狀況,當咱們的目標值出如今數組最後一位的狀況,因此當數組遍歷結束後沒有返回值,則咱們須要返回數組最後一位,下面咱們看一下動圖解析。


題目代碼


HashSet


這個方法也是比較容易實現的,咱們利用 HashSet 來完成。HashSet 在咱們刷題時出現頻率是特別高的,它是基於  HashMap 來實現的,是一個不容許有重複元素的集合。那麼在這個題解中,它起到什麼做用呢?

解題思路以下,咱們依次遍歷元素並與 HashSet  內的元素進行比較,若是 HashSet 內沒有該元素(說明該元素第一次出現)則存入,如果  HashSet  已經存在該元素(第二次出現),則將其從 HashSet  中去除,並繼續遍歷下一個元素。最後 HashSet 內剩下的則爲咱們的目標數。思路和咱們以前說過的括號匹配問題相似,咱們一塊兒來看一下動圖解析吧。

題目代碼


該方法也很容易想到,咱們首先將其排序,而後遍歷數組,若是棧爲空則將當前元素壓入棧,若是棧不爲空,若當前元素和棧頂元素相同則出棧,繼續遍歷下一元素,若是當前元素和棧頂元素不一樣的話,則說明棧頂元素是隻出現一次的元素,咱們將其返回便可。這個題目也可使用隊列作,思路一致,咱們就不在這裏說明啦。下面咱們看下動圖解析。


題目代碼


求和法

這個方法也比較簡單,也是藉助我們的 HashSet 具體思路以下,咱們經過 HashSet 保存數組內的元素,而後進行求和(setsum),那麼獲得的這個和則爲去除掉重複元素的和,咱們也能夠獲得全部元素和(numsum)。由於咱們其餘元素都出現兩次,僅有一個元素出現一次,那咱們經過 setsum * 2 - numsum 獲得的元素則爲出現一次的數。

求和解法

上面咱們的 SetSum  * 2 - NumSum = z 也就是咱們所求的值, 是否是感受很簡單呀。

題目代碼


位運算

這個方法主要是藉助我們的位運算符 ^ 按位異或,咱們先來了解一下這個位運算符。

按位異或(XOR)運算符「^」是雙目運算符。其功能是參與運算的兩數各對應的二進位相異或,當兩數對應的二進位相異時,結果爲1。相同時爲0。

任何數和0異或,仍爲自己:a⊕0 = a
任何數和自己異或,爲0:a⊕a = 0 
異或運算知足交換律和結合律:a⊕b⊕a = (a⊕a)⊕b = 0⊕b = b

例:


咱們經過上面的例子瞭解了異或運算,對應位相異時得 1,相同時得 0,那麼某個數跟自己異或時,由於對應位都相同因此結果爲 0 , 而後異或又知足交換律和結合律。則


題目代碼


本題一共介紹了6種解題方法,確定還有別的方法,歡迎你們討論。你們能夠在作題的時候一題多解。這樣能大大提升本身解題能力。下面咱們來看一下這些方法如何應用到其餘題目上。

只出現一次的數Ⅱ

給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現了三次。找出那個只出現了一次的元素。

示例 1:

輸入: [2,2,3,2] 輸出: 3

示例 2:

輸入: [0,1,0,1,0,1,99] 輸出: 99

題目很容易理解,剛纔的題目是其餘元素出現兩次,目標元素出現一次,該題是其餘元素出現三次,目標元素出現一次,因此咱們徹底能夠藉助上題的一些作法解決該題。

求和法

咱們在上題中介紹了求和法的解題步驟,如今該題中其餘元素都出現三次,咱們的目標元素出現一次,因此咱們利用求和法也是徹底 OK 的。下面咱們來看具體步驟吧。

1.經過遍歷數組獲取全部元素的和以及 HashSet 內元素的和。

2.(SumSet  *  3  -  SumNum)/ 2便可,除以 2 是由於咱們減去以後獲得的是 2 倍的目標元素。

注:這個題目中須要注意溢出的狀況 。

題目代碼

這個題目用 HashMap 和排序查找確定也是能夠的,你們能夠本身寫一下,另外咱們在第一題中有個利用異或求解的方法,可是這個題目是出現三次,咱們則不能利用直接異或來求解,那還有其餘方法嗎?

位運算

這個方法主要作法是將咱們的數的二進制位每一位相加,而後對其每一位的和取餘 ,咱們看下面的例子。


那麼咱們爲何要這樣作呢?你們想一下,若是其餘數都出現 3 次,只有目標數出現 1 次,那麼每一位的 1 的個數無非有這2種狀況,爲 3 的倍數(全爲出現三次的數) 或 3 的倍數 +1(包含出現一次的數)。這個 3 的倍數 +1 的狀況也就是咱們的目標數的那一位。

題目代碼

   

咱們來解析一下咱們的代碼

<<     二進制左移運算符。左操做數的值向左移動右操做數指定的位數。
>>     二進制右移運算符。左操做數的值向右移動右操做數指定的位數。

另外咱們的代碼中還包含了 a & 1  和  a | 1 這有什麼做用呢?繼續看下圖

&       按位與運算符:參與運算的兩個值,若是兩個相應位都爲1,則該位的結果爲1,不然爲0


由於咱們 a & 1 中 1 只有最後一位爲 1,其他位皆爲 0 ,因此咱們發現 a & 1的做用就是判斷 a 的最後一位是否爲 1 ,若是 a 的最後一位爲 1 ,a & 1 = 1,不然爲 0 。因此咱們還能夠經過這個公式來判斷 a 的奇偶性。

|        按位或運算符:只要對應的二個二進位有一個爲1時,結果位就爲1。


這個公式的做用就是將咱們移位後的 res 的最後一位 0 變爲 1。這個 1 也就表明着咱們只出現一次元素的某一位。

只出現一次的數Ⅲ

給定一個整數數組 nums,其中剛好有兩個元素只出現一次,其他全部元素均出現兩次。找出只出現一次的那兩個元素。

示例 :

輸入: [1,2,1,3,2,5] 輸出: [3,5]

這個也很容易理解,算是對第一題的升級,第一題有 1 個出現 1次的數,其他出現兩次,這個題目中有 2 個出現 1次的數,其他數字出現兩次。那麼這個題目咱們怎麼作呢?咱們看一下能不能利用第一題中的作法解決。

HashSet

這個作法和咱們第一題的作法一致,只要理解了第一題的作法,這個很容易就能寫出來,有一點不一樣的是,第一題的 HashSet 裏面最後保留了一個元素,該題保留兩個元素。

題目代碼


位運算

第一題中,咱們能夠經過異或運算直接求出目標數,可是咱們第二題中不能直接用異或,是由於其餘數字都出現三次,目標數出現一次。在這個題目中其餘數字出現兩次,目標數出現一次,可是此次的目標數爲兩個,咱們直接異或運算的話,獲得的數則爲兩個目標數的異或值,那麼咱們應該怎麼作呢?

咱們試想一下,若是咱們先將元素分紅兩組,而後每組包含一個目標值,那麼異或以後,每組獲得一個目標值,那麼咱們不就將兩個目標值求出了嗎?

例:a,b,a,b,c,d,e,f,e,f     分組後

A組:a, a , b, b, c     異或獲得 c

B組:e, e,  f,  f,  d     異或獲得 d

原理懂了,那麼咱們應該依據什麼規則對其進行分類呢?

c , d  兩個不一樣的數,那麼二進制上一定有一位是不一樣的,那麼咱們就能夠根據這一位(分組位)來將 c , d 分到兩個組中,數組中的其餘元素,要麼在 A 組中,要麼在 B 組中。

咱們應該怎麼獲得分組位呢?

咱們讓 c , d 異或便可,異或運算就是對應位不一樣時得 1 ,異或以後值爲 1 的其中一位則爲咱們分組。

例 001 ⊕  100 = 101,咱們能夠用最右邊的 1 或最左邊的 1 作爲分組位,數組元素中,若咱們將最右邊的 1 做爲咱們的分組位,最後一位爲 0 的則進入 A 組,爲 1 的進入 B 組。

那麼咱們應該怎麼藉助分組位進行分組呢?

咱們處理 c , d 的異或值,能夠僅保留異或值的分組位,其他位變爲 0 ,例如 101 變成 001或 100

爲何要這麼作呢?在第二題提到,咱們能夠根據 a & 1 來判斷 a 的最後一位爲 0 仍是爲 1,因此咱們將 101 變成 001 以後,而後數組內的元素  x & 001  便可對 x 進行分組 。一樣也能夠 x & 100 進行分組.

那麼咱們如何才能僅保留分組位,其他位變爲 0 呢?例 101 變爲 001

咱們能夠利用 x & (-x) 來保留最右邊的 1


題目代碼:

本文分享自微信公衆號 - 五分鐘學算法(CXYxiaowu)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索