Leetcode HOT 100 —— 448.找到所有数组中消失的数字

119 阅读2分钟

Leetcode HOT 100 —— 448.找到所有数组中消失的数字

数组

题目描述

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

进阶: 你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。

解题思路

通过 索引 找到缺失的数字。

解题代码

第一种解法 使用另一个数组存放出现过的值

var findDisappearedNumbers = function(nums) {
  let arr = [], res = []
  for(let i = 0; i < nums.length; i++) {
      arr[nums[i]-1] = nums[i]
  }
  for(let i = 0; i < arr.length; i++) {
      if(arr[i] == null) {
          res.push(i+1)
      }
  }
  return res
};

时间复杂度虽然可以满足,但是不符合进阶要求。空间复杂度是 O(m)

第二种解法 减1取反

对每个值减 1后得到的数对应索引位置的值取相反数,最后判断值为非负数的索引加 1为缺失的数字

索引01234567
43278231
-4-3-2-782-3-1
const len = nums.length
  for(let i = 0; i < len; i++) {
    let x = nums[i] -1
    // 如果值小于0,就取反后再减一。因为会出现重复的数字,所以做这步操作
    if(nums[i] < 0) x = -nums[i] - 1
    // 如果值小于0,跳过。避免出现多次取反的情况,只取一次反
    if(nums[x] < 0) continue
    nums[x] = -nums[x]
  }
  const result = []
  for(let i = 0; i< len; i++) {
    // 筛选,找到没有被取反的值的索引
    if(nums[i] > 0) {
      result.push(i+1)
    }
  }
  return result

第三种解法 减1取余

上一种思路是对值取反,这次我们为他加数组的长度后取余获取原来的值

索引01234567
43278231
值 + len1211101582119
-1取余32167120

减1取余后没有 4 和 5 的索引,符合预期,代码实现一下。

var findDisappearedNumbers = function(nums) {
  const len = nums.length
  for(let i = 0; i < len; i++) {
    // 减1后取len的余数,恢复原来的值
    let x = (nums[i] - 1) % len
    nums[x] += len
  }
  const result = []
  for(let i = 0; i< len; i++) {
    // 只有未改变的值小于 len,找到后对索引加1
    if(nums[i] <= len) {
      result.push(i+1)
    }
  }
  return result
};

类似题目:剑指 Offer 53- II. 0~n-1中缺失的数字

题目描述:

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

这题虽然和上题很相似,但还是有坑,做完上面的题后,再看这题,你会很直接的想复杂了。这题必上题要简单的多,因为他只找一个不在数组中的数字。我直接写解法

第一种解法 一次循环遍历

思路非常简单,每次迭代判断,索引和对应的值是否相等,不相等就返回这个索引并结束循环。如果循环到最后都不符合判断条件,说明它缺失数组length的数字。那么就返回 num.length

var missingNumber = function(nums) {
  for(let i = 0; i < nums.length; i++) {
    if(nums[i] !== i) return i
  }
  return nums.length
};

第二种解法 二分查找

var missingNumber = function(nums) {
  let left =0, right = nums.length - 1
  while(left <= right){
      let mid = Math.floor((left + right) / 2)
      if(nums[mid] == mid){
          left = mid +1
      }else{
          right = mid -1
      }
  }
  return left
};