[消失的数字] 还能用位运算解决?

来源:力扣(LeetCode)
链接:面试题 17.04. 消失的数字

题目

数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
注意:本题相对书上原题稍作改动

输入:[3,0,1]
输出:2

输入:[9,6,4,2,3,5,7,0,1]
输出:8

题目解析

首先了解题目大意:0 — n 中少了一个数字,让我们求出
我现在所能想到的,有三种方法:

  1. 哈希表,通过使用哈希表对完整的 0 — n 计数,最终得到出现次数为 0 的数;
  2. 使用二分查找,在完整的 0 — n 上进行二分查找,最终找到要求数;
  3. 使用位运算解决

接下来唠叨一下方法二与方法三:

二分查找

思想与相同,通过构造一个假想的完整的 0 — n ,并对其进行二分查找,比如二分查找的中值为4,那么我们在原数组中找小于等于4的个数,如果不含缺失数的话,应该能找到(0, 1, 2, 3, 4)五个数,但如果找到的数小于等于4个,则说明0—4中含有缺失数,则right = mid, 反之,left = mid + 1;
对这种寻找思想感兴趣的话,还可以看这篇文章用二分法解决【寻找重复数】问题

代码

class Solution {
    public int missingNumber(int[] nums) {
        //二分查找
        Arrays.sort(nums);
        int len = nums.length;
        if(len == 1){
            return nums[0] == 0 ? 1 : 0;//特殊情况,当n == 1 的时候,应包含[0, 1]
        }
        int left = 0, right = len;//左指针,右指针
        while(left < right){//循环条件
            int mid = left + (right - left) / 2;//中值
            int cnt = 0;//计数
            for(int num :nums){
                if(num <= mid){//原数组中小于等于mid的个数(正常应该有 mid+1 个)
                    cnt += 1;
                }
            }
            if(cnt <= mid){//如果不到 mid+1 个,即 <= mid
                right = mid;//则 0——mid 中有缺失
            }else{//反之
                left = mid + 1;// mid+1 —— len 有缺失
            }
        }
        return left;//返回left或right(由于循环条件此时left == right)
    }
}

位运算

这道题目如何用位运算解决呢,当我们看到这道题目的时候,发现他与只出现一次的数字(位运算java)很相似,不同的是,这道题目中有一个数出现的次数是0次,如果让每个数出现的次数都加1,那么两道题好像就一样了。
同样的,我们使用异或的特点:

相同数异或 结果为0
不同数异或 结果为1
一个数与0异或 结果为其本身。

代码

class Solution {
    public int missingNumber(int[] nums) {
        //位运算
        int len = nums.length;//数组中应含有 0——len 即 len+1 个数,少一个数,则只有 len 个数
        int m = 0, res = 0;
        for(int num : nums){//循环 len 次,0——len-1 个数
            res ^= num ^ m;
            m += 1;//用m来表示不缺失的 0——len-1 的 len 个数
        }
        return res ^ len;//记得带上第 len 个数
    }
}

你可能感兴趣的:(位运算,二分法)