Given an array containing n distinct numbers taken from 0, 1, 2, ..., n
, find the one that is missing from the array.
For example,
Given nums = [0, 1, 3]
return 2
.
Note:
Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?
這道題給我們n個數字,是0到n之間的數但是有一個數字去掉了,讓我們尋找這個數字,要求線性的時間復雜度和常數級的空間復雜度。那么最直觀的一個方法是用等差數列的求和公式求出0到n之間所有的數字之和,然后再遍歷數組算出給定數字的累積和,然后做減法,差值就是丟失的那個數字,參見代碼如下:
解法一:
class Solution { public: int missingNumber(vector<int>& nums) { int sum = 0, n = nums.size(); for (auto &a : nums) { sum += a; } return 0.5 * n * (n + 1) - sum; } };
這題還有一種解法,使用位操作Bit Manipulation來解的,用到了異或操作的特性,相似的題目有Single Number 單獨的數字, Single Number II 單獨的數字之二和Single Number III 單獨的數字之三。那么思路是既然0到n之間少了一個數,我們將這個少了一個數的數組合0到n之間完整的數組異或一下,那么相同的數字都變為0了,剩下的就是少了的那個數字了,參加代碼如下:
解法二:
class Solution { public: int missingNumber(vector<int>& nums) { int res = 0; for (int i = 0; i < nums.size(); ++i) { res ^= (i + 1) ^ nums[i]; } return res; } };
這道題還可以用二分查找法來做,我們首先要對數組排序,然后我們用二分查找法算出中間元素的下標,然后用元素值和下標值之間做對比,如果元素值大於下標值,則說明缺失的數字在左邊,此時將right賦為mid,反之則將left賦為mid+1。那么看到這里,作為讀者的你可能會提出,排序的時間復雜度都不止O(n),何必要多此一舉用二分查找,還不如用上面兩種方法呢。對,你說的沒錯,但是在面試的時候,有可能人家給你的數組就是排好序的,那么此時用二分查找法肯定要優於上面兩種方法,所以這種方法最好也要掌握以下~
解法三:
class Solution { public: int missingNumber(vector<int>& nums) { sort(nums.begin(), nums.end()); int left = 0, right = nums.size(); while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] > mid) right = mid; else left = mid + 1; } return right; } };
在CareerCup中有一道類似的題,5.7 Find Missing Integer 查找丟失的數,但是那道題不讓我們直接訪問整個int數字,而是只能訪問其二進制表示數中的某一位,強行讓我們使用位操作Bit Manipulation來解題,也是蠻有意思的一道題。