消失的数字(一个/多个)

151 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

数组包含从0到n的所有整数,但其中缺了一个,找出那个缺失的整数。

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

数组包括0到3,其中缺少2。

二、思路分析:

根据题目我们知道,数组里面的值是0~n,那么数组的索引也是0~n,根据这个思路,我们可以根据索引找到对应的值,判断值存不存在。

function missingNumber (nums) {
  let set = new Set()
  for (let i = 0; i < nums.length; i++) {
    set.add(nums[i])
  }
  for (let i = 0; i < nums.length; i++) {
    if (set.has(i) === false) {
      return i
    }
  }
  return 0
}

使用set标记法,来判断值是否存在。时间复杂度位O(n),空间复杂度位O(n)。

除了标记法,我们还可以对数组进行排序,排序后遍历数组,数组索引与对应的值对比,不相同就输出。

function missingNumber (nums) {
  let arr = nums.sort((a, b) => a - b)
  for (let i = 0; i < nums.length; i++) {
    if (arr[i] !== i) {
      return i
    }
  }
  return 0
}

使用排序法,来判断值是否存在。时间复杂度位O(NloginN)。

上面两种发放都不是最好的,第三方方法是等差数列求和公式。

现在有个等差数列 0, 1, 2,…, n, 其中少了某⼀个数字, 请你把它找出来。 那这个数字不就是 sum(0,1,…n) - sum(nums)嘛?

function missingNumber (nums) {
  let n = nums.length
  let expect = (0 + n) * (n + 1) / 2
  let total = nums.reduce((a, b) => a + b, 0)
  return expect - total
}

等差数列求和公式,前n项和公式为:Sn=n*a1+n(n-1)d/2或Sn=n(a1+an)/2 。

通过等差数列求和是找一个消失数字的最佳实践方法。

到目前为止我们已经掌握了找一个消失的数字,那么加大题目难度,找到所有数组中消失的数字。

function missingNumber (nums) {
  let set = new Set()
  let res = []
  for (let i = 0; i < nums.length; i++) {
    set.add(nums[i])
  }
  for (let i = 0; i <= nums.length; i++) {
    if (set.has(i) === false) {
      res.push(i)
    }
  }
  return res
}

通过简单的修改一下代码就可以实现,也是使用 set 来标记。

我们用一个哈希表记录数组 nums 中的数字,由于数字范围均在 [0,n] 中,记录数字后我们再利用哈希表检查 [0,n] 中的每一个数是否出现,从而找到缺失的数字。

四、总结:

在算法的实现过程中其实经常使用哈希表记录数组的数字,但是会导致空间复杂度变成O(n),所以在编写算法的时候要检查自己的代码是否可以降低复杂度,看下是否可以通过数学公式来完成计算。