本文首發於公眾號「五分鐘學演算法」,是圖解 LeetCode 系列文章之一。
個人網站:www.cxyxiaowu.com
今天分享一道很簡單的演算法題。
題目來源於 LeetCode 上第 268 號問題:缺失數字。題目難度為 Easy,目前通過率為 50.2% 。
題目描述
給定一個包含 0, 1, 2, ..., n
中 n 個數的序列,找出 0 .. n 中沒有出現在序列中的那個數。
說明:
你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
題目解析
這道題目有三種解法。
解法一:異或法
和之前那道 只出現一次的數字 很類似:
只出現一次的數字: 給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
如果我們補充一個完整的陣列和原陣列進行組合,那所求解的問題就變成了 只出現一次的數字。
將少了一個數的陣列與 0 到 n 之間完整的那個陣列進行異或處理,因為相同的數字異或會變為了 0 ,那麼全部數字異或後,剩下的就是少了的那個數字。
程式碼實現1
class Solution {
public int missingNumber(int[] nums) {
int res = 0;
//注意陣列越界情況
for (int i = 0; i < nums.length;i++){
// i 表示完整陣列中的數字,與原陣列中的數字 nums[i] 進行異或,再與儲存的結果異或
res = res^i^nums[i];
}
//最後需要與迴圈中無法使用到的那個最大的數異或
return res^i;
}
}
複製程式碼
程式碼實現2
class Solution {
public int missingNumber(int[] nums) {
int res = nums.length;
for (int i = 0; i < nums.length; ++i){
res ^= nums[i];
res ^= i;
}
return res;
}
}
複製程式碼
解法二:求和法
- 求出 0 到 n 之間所有的數字之和
- 遍歷陣列計算出原始陣列中數字的累積和
- 兩和相減,差值就是丟失的那個數字
//小吳之前擔心會資料溢位,不過估計這題考察的不是這個,所以測試用例沒寫這種吧,還是能 AC 的
class Solution {
public int missingNumber(int[] nums) {
int n = nums.length;
int sum = (n+0)*(n+1)/2;
for (int i=0; i<n; i++){
sum -= nums[i];
}
return sum;
}
}
複製程式碼
解法三:二分法
將陣列進行排序後,利用二分查詢的方法來找到缺少的數字,注意搜尋的範圍為 0 到 n 。
- 首先對陣列進行排序
- 用元素值和下標值之間做對比,如果元素值大於下標值,則說明缺失的數字在左邊,此時將 right 賦為 mid ,反之則將 left 賦為 mid + 1 。
注:由於一開始進行了排序操作,因此使用二分法的效能是不如上面兩種方法。
public class Solution {
public int missingNumber(int[] nums) {
Arrays.sort(nums);
int left = 0;
int right = nums.length;
while (left < right){
int mid = (left + right) / 2;
if (nums[mid] > mid){
right = mid;
}else{
left = mid + 1;
}
}
return left;
}
}
複製程式碼