讀完本文,你能夠去力扣拿下以下題目:java
-----------github
以前也有文章寫過幾個有趣的智力題,今天再聊一道巧妙的題目。算法
題目很是簡單:數組
給一個長度爲 n 的數組,其索引應該在 [0,n)
,可是如今你要裝進去 n + 1 個元素 [0,n]
,那麼確定有一個元素裝不下嘛,請你找出這個缺失的元素。數據結構
這道題不難的,咱們應該很容易想到,把這個數組排個序,而後遍歷一遍,不就很容易找到缺失的那個元素了嗎?app
或者說,藉助數據結構的特性,用一個 HashSet 把數組裏出現的數字都儲存下來,再遍歷 [0,n]
之間的數字,去 HashSet 中查詢,也能夠很容易查出那個缺失的元素。學習
排序解法的時間複雜度是 O(NlogN),HashSet 的解法時間複雜度是 O(N),可是還須要 O(N) 的空間複雜度存儲 HashSet。code
PS:我認真寫了 100 多篇原創,手把手刷 200 道力扣題目,所有發佈在 labuladong的算法小抄,持續更新。建議收藏,按照個人文章順序刷題,掌握各類算法套路後投再入題海就如魚得水了。排序
第三種方法是位運算。
對於異或運算(^
),咱們知道它有一個特殊性質:一個數和它自己作異或運算結果爲 0,一個數和 0 作異或運算仍是它自己。
並且異或運算知足交換律和結合律,也就是說:
2 ^ 3 ^ 2 = 3 ^ (2 ^ 2) = 3 ^ 0 = 3
而這道題索就能夠經過這些性質巧妙算出缺失的那個元素。好比說 nums = [0,3,1,4]
:
爲了容易理解,咱們假設先把索引補一位,而後讓每一個元素和本身相等的索引相對應:
這樣作了以後,就能夠發現除了缺失元素以外,全部的索引和元素都組成一對兒了,如今若是把這個落單的索引 2 找出來,也就找到了缺失的那個元素。
如何找這個落單的數字呢,只要把全部的元素和索引作異或運算,成對兒的數字都會消爲 0,只有這個落單的元素會剩下,也就達到了咱們的目的。
int missingNumber(int[] nums) { int n = nums.length; int res = 0; // 先和新補的索引異或一下 res ^= n; // 和其餘的元素、索引作異或 for (int i = 0; i < n; i++) res ^= i ^ nums[i]; return res; }
因爲異或運算知足交換律和結合律,因此老是能把成對兒的數字消去,留下缺失的那個元素的。
至此,時間複雜度 O(N),空間複雜度 O(1),已經達到了最優,咱們是否就應該打道回府了呢?
若是這樣想,說明咱們受算法的毒害太深,隨着咱們學習的知識愈來愈多,反而容易陷入思惟定式,這個問題其實還有一個特別簡單的解法:等差數列求和公式。
題目的意思能夠這樣理解:如今有個等差數列 0, 1, 2,..., n,其中少了某一個數字,請你把它找出來。那這個數字不就是 sum(0,1,..n) - sum(nums)
嘛?
int missingNumber(int[] nums) { int n = nums.length; // 公式:(首項 + 末項) * 項數 / 2 int expect = (0 + n) * (n + 1) / 2; int sum = 0; for (int x : nums) sum += x; return expect - sum;
你看,這種解法應該是最簡單的,但說實話,我本身也沒想到這個解法,並且我去問了幾個大佬,他們也沒想到這個最簡單的思路。相反,若是去問一個初中生,他也許很快就能想到。
作到這一步了,咱們是否就應該打道回府了呢?
若是這樣想,說明咱們對細節的把控還差點火候。在用求和公式計算 expect
時,你考慮過整型溢出嗎?若是相乘的結果太大致使溢出,那麼結果確定是錯誤的。
PS:我認真寫了 100 多篇原創,手把手刷 200 道力扣題目,所有發佈在 labuladong的算法小抄,持續更新。建議收藏,按照個人文章順序刷題,掌握各類算法套路後投再入題海就如魚得水了。
剛纔咱們的思路是把兩個和都加出來而後相減,爲了不溢出,乾脆一邊求和一邊減算了。很相似剛纔位運算解法的思路,仍然假設 nums = [0,3,1,4]
,先補一位索引再讓元素跟索引配對:
咱們讓每一個索引減去其對應的元素,再把相減的結果加起來,不就是那個缺失的元素嗎?
public int missingNumber(int[] nums) { int n = nums.length; int res = 0; // 新補的索引 res += n - 0; // 剩下索引和元素的差加起來 for (int i = 0; i < n; i++) res += i - nums[i]; return res; }
因爲加減法知足交換律和結合律,因此老是能把成對兒的數字消去,留下缺失的那個元素的。
至此這道算法題目經歷九曲十八彎,終於再也沒有什麼坑了。
_____________
個人 在線電子書 有 100 篇原創文章,手把手帶刷 200 道力扣題目,建議收藏!對應的 GitHub 算法倉庫 已經得到了 70k star,歡迎標星!