Leetcode 268. 丢失的数字

0x01 题目要求

给定一个包含 [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 中的所有数字都 独一无二

0x02 解题思路

哈希集合

  • 有题意可知,我们 需要在长度为 n 的数组中,找到 0 - n 之间丢失的那个数字
  • 最开始我想到的就是使用 哈希集合 来求解
  • 创建一个哈希集合,遍历一次元素数组,将每一个元素都存放在哈希集合当中
  • 当所有元素存放完后,需要 再遍历一次 0 - n ,在哈希集合中找到不存在的那个元素值

代码如下:

// 哈希集合
class Solution
{
    
    
public:
    int missingNumber(vector<int>& nums)
    {
    
    
        int n = nums.size();
		// 创建一个哈希集合,用于存放 nums 数组中所有值后查找丢失值
        unordered_set<int> hashset;
		// 循环遍历 nums 中的所有元素值为 e
        // 并将每一个元素值 e 插入到哈希集合中
        for (int e : nums)
            hashset.insert(e);
		// 遍历 0 - n ,在哈希集合中查找到丢失的元素
        for (int i=0;i<=n;i++)
            if (!hashset.count(i))
				// 当没有找到 0 - n 中的某一个值时
                // 代表这个值为丢失值,直接将 i 返回即可
                return i;
        return n;
    }
};

排序

  • 很明显使用哈希集合求解需要花费大量的时间
  • 既然每一个元素都在 0 - n 之间,且只出现一次
  • 那么我们可以 将数组元素先排序
  • 然后 再遍历一遍排序完的数组
  • 当当前元素值与位置下标不符合时
  • 代表当前下标位置的值即是丢失的值

代码如下:

// 排序
class Solution
{
    
    
public:
    int missingNumber(vector<int>& nums)
    {
    
    
        int n = nums.size();
		// 使用 C++ 标准库中的排序函数将 nums 元素进行排序
		// 默认排序方法为 从小到大
        sort(nums.begin(), nums.end());
		// 循环遍历排序完 nums 数组中所有值
        for (int i=0;i<n;i++)
			// 当当前 nums[i] != i ,即当前值与位置值不符时
			// 代表已经找到了丢失值,此时将 i 返回即可
            if (nums[i] != i)
                return i;
        return n;
    }
};

异或

  • 在之前文章 Leetcode 136.只出现一次的数字Ⅰ 中用到过异或进行求解
  • 具体的异或知识可以点链接跳转查看
  • 以此作为启发,我们 先将一个初始化为 0 的变量 result 与 nums 中的每一个元素进行异或
  • 然后再将 result 与 0 - n 的每一个元素进行一次异或
  • 那么,在 0 - n 中,只有丢失的那个值只进行了一次异或
  • 其他值都进行了两次异或相当于 A ^ A ^ B ^ B … ^ Y ^ Y ^ Z = 0 ^ Z
  • 最后就是 0 与 丢失的那个值进行一次异或
  • 0 与任何值异或结果都为任何值本身
  • 最后返回 result 即可

代码如下:

// 异或
class Solution
{
    
    
public:
    int missingNumber(vector<int>& nums)
    {
    
    
        int n = nums.size();
		// 创建一个结果变量 result = 0
        int result = 0;
		// 先将 nums 中的每一个元素值都与 result 相异或
        for (int num : nums)
            result ^= num;
		// 再将 result 与 0 - n 每一个元素相异或
		// 由于只有丢失的那个值与 result 异或一次
		// 其他值都异或了两次,异或两次的值为 0 
		// 最后就相当于 0 与 丢失值相互异或
		// 最后 result 就等于丢失值
        for (int i=0;i<=n;i++)
            result ^= i;
		// 返回 result 即可
        return result;
    }
};

数学求解

  • 在 0 - n 之间找到数组中丢失的值
  • 在这里我们使用 高斯求和 公式直接算得 sum 值
  • 那么当我们把 0 - n 之间所有元素相加求和获得 sum 之后
  • 再用 sum 减去当前 nums 数组中的每一个 num 元素
  • 最后留下的数值,就是我们需要找的丢失的值

代码如下:

// 数学求解
class Solution
{
    
    
public:
    int missingNumber(vector<int>& nums)
    {
    
    
        int n = nums.size();
        // 将 0 - n 的所有元素相加求和的值记为 sum
        // 通过高斯求和公式即可算出 sum 的大小
        int sum = n * (n + 1) / 2;
        // 遍历循环 nums 数组中的每一个元素记为 num
        // 将每一个元素 num 都从 sum 中减去
        for (int num : nums)
            sum -= num;
        // 减到最后剩下的值即为丢失的值
        return sum;
    }
};

0x03 测试结果

哈希集合

  • 时间复杂度:O(n),遍历数组元素的时间复杂度为O(n),判断 0 - n 的每个整数是否在哈希集合中的时间复杂度也是O(n)。
  • 空间复杂度:O(n),n 为 nums 的长度,哈希集合需要存放 n 个数组元素。

在这里插入图片描述

在这里插入图片描述

排序

  • 时间复杂度:O(nlogn),排序的时间复杂度为O(nlogn),遍历数组找到丢失值的时间复杂度为O(n),因此总的时间复杂度为O(nlogn)。
  • 空间复杂度:O(logn),空间复杂度只要是取决于在排序时递归调用栈的空间。
    在这里插入图片描述

异或

  • 时间复杂度:O(n),异或数组的时间复杂度为O(n),异或 0 - n 之间元素的时间复杂度也是O(n)。
  • 空间复杂度:O(1),并不需要开辟额外的空间。
    在这里插入图片描述

数学求解

  • 时间复杂度:O(n),高斯求和 sum 需要O(1)的时间,遍历 nums 数组每次减去一个元素的时间复杂度为O(n)。
  • 空间复杂度:O(1),并不需要开辟额外的空间。
    在这里插入图片描述

Good Luck!

猜你喜欢

转载自blog.csdn.net/weixin_46992165/article/details/126558844