算法题之消失的数字

消失的数字

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

示例 4:

输入:nums = [0]
输出:1
解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。

提示:

  • n == nums.length
  • 1 <= n <= 104
  • 0 <= nums[i] <= n
  • nums 中的所有数字都 独一无二

进阶:你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?

解题思路

由题意可知,长度为n的数组中,有n个不同的数字;而题目中说的,在[0, n]范围内,总共有n+1个数字,我们需要找到缺少的那一个数字并返回。

我们尝试用简单一点儿的方法找到缺少的数字:

  1. 我们可以初始化一个长度为n+1的boolean型数组m,这样它的下标范围为[0, n],正好就是全部的数字范围,然后我们先遍历题目中提供的长度为n的数组nums,把数组nums的值作为数组m的下标,并设置数组m的元素值为true;接着我们再遍历一遍数组m,找到元素值为false的下标值,这个下标即缺少的数字。
  2. 我们可以对数组nums排序,使其元素值升序排列;然后我们可以用二分法,比较数组nums的下标和对应的元素值,我们先找下标为n/2处的元素,如果下标等于对应的元素值,说明在[0, n/2]范围内的下标和元素值都相等,则我们用二分法在[n/2 + 1, n - 1]范围内查找;如果下标小于元素值,则我们用二分法在[0, n/2 -1]范围内查找。按照这个思路,直到我们找到确实的数字即可。

在上面两种方法中,其中方法一是线性时间复杂度,但是也用到了线性的额外空间;而方法二,只用到了常数的额外空间,但是时间复杂度超过了线性。

如何实现线性时间复杂度、又仅使用额外常数空间的呢?这里提供两种解法:

  • 解法一:我们可以用算出0到n之和,然后减去nums的元素值,得到的差即为缺少的数字
  • 解法二:我们可以用到一种运算方式:异或运算。

两个相同的数字之间异或,会得到0;而0与任何一个数字之间异或,会得到这个数字。也就是说,重复的数字异或的结果是0,而唯一的数字异或的结果就是这个数字,所以我们可以运用异或运算,找到缺少的数字。

我们来分析一下,数字nums的长度为n,它的下标范围为[0, n - 1],元素值的范围在[0, n]之间,但是只有n个数字。我们需要初始化一个变量k,然后用k分别与下标和相应的元素值做异或运算;那么变量k应该初始化为哪个值呢?我们应该初始化为n,这样我们就有了在完整的范围[0, n]之间的n+1个值,然后和范围[0, n]之间的n个元素值做异或运算,最后就可以得到那个缺少的数字了。

具体代码如下:

class Solution {
    public int missingNumber(int[] nums) {
        int loss = nums.length;
        for(int i = 0; i < nums.length; i++){
            loss ^= i ^ nums[i];
        }

        return loss;
    }
}

复杂度分析

  • 时间复杂度:O(n),需要遍历一遍数组nums。
  • 空间复杂度:O(1),使用了常量的额外空间。
  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值