这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
找到所有数组中消失的数字(题号448)
题目
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
示例 2:
输入:nums = [1,1]
输出:[2]
提示:
n == nums.length1 <= n <= 1051 <= nums[i] <= n
进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
链接
解释
这题啊,这题是茴字的五种写法
表面上看上去确实挺简单的,能想到的解法也很多,主要思路还是一个。
扫一遍数组,对符合条件的数字进行记录,然后扫第二遍,进行相应的处理,因为解法过多,此处不多做解释了,👇会依次介绍。
自己的答案(includes)
这可以说是最简单的一种方法了,无需进行任何额外的操作,根据题意,只需要依次进行数字的累计,因为数字的范围是[1, n],所以依次循环数字,如果该数字不在数组中,直接推入res中,最后循环完成返回res即可。
var findDisappearedNumbers = function(nums) {
const res = []
let count = 1
while (count <= nums.length) {
if (!nums.includes(count)) res.push(count)
count++
}
return res
};
使用for循环也是可以的,个人喜好
自己的答案(set+初始化)
也可以直接使用set处理nums,如此数组中的重复数字会被直接过滤掉,后续再使用类似上面的做法,利用set.has来判断当前数字是否在set中,如果在就算了,如果不在就推入到res中去。
这种做法比上一种做法的速度会快些,因为has的性能比includes好些,但对应的,有了set后,空间复杂度就变成O(n)了,内存占用会比上一种方法多些,典型的空间换时间。
var findDisappearedNumbers = function(nums) {
const set = new Set(nums)
const res = []
let count = 1
while (count <= nums.length) {
if (!set.has(count)) res.push(count)
count++
}
return res
};
自己的答案(set+原地修改)
这种做法和上面的做法本质上没什么区别,重点是不需要res,最后只需要返回修改过的set就好
首先也是初始化一个set,之后开始循环数组,如果该元素在set中存在,那就从set中删掉这个元素,如果不存在,就添加一下,这就完事了
最后剩下的就是没有在nums中出现的元素了,非常简单,同时也省去了res这个变量,缺点可能就是add、set、delete这些操作可能会比较耗费时间吧。
var findDisappearedNumbers = function(nums) {
const set = new Set(nums)
for (let i = 1; i <= nums.length; i++) {
if (set.has(i)) {
set.delete(i)
} else {
set.add(i)
}
}
return Array.from(set)
};
更好的方法(两次循环)
👆的三种方法其实都没有符合题意,空间复杂度不达标,即使达标了性能损耗也会比较大,那有没有什么更好的方法呢?
显然是有的,官方就提出了一种在nums基础上进行修改的方法。
让我们回到数组的定义上,数组的本质其实是特性类型key的对象,也就是index。那么,是否可以结合index和value来进行一波配合,来统计出不存在的元素呢?
首先,可以将值和index进行转化,也就是nums作为index,将找到的所有index的value添加n,那么此时如果有的数字没有出现,那么该数字代表的index的值肯定不会大于n,如果已经出现了,由于刚才的操作,值会比n大,那么只需要进行第二次过滤,如果当前数字的值小于等于n,那就证明该数字没有出现过,推入res即可。
说起来可能会比较绕,看看代码就懂了👇:
var findDisappearedNumbers = function(nums) {
const len = nums.length
const res = []
for (const num of nums) {
const x = (num - 1) % len
nums[x] += len
}
for (let i = 0; i < len; i++) {
if (nums[i] <= len) res.push(i + 1)
}
return res
};
用了两次for循环:一次用来更新数组,确定哪些数字是存在的;第二次用来进行记录,将不存在的数字推入到res中去。
整体来说比较简单,就是很难想到罢了,没有办法~
PS:想查看往期文章和题目可以点击下面的链接:
这里是按照日期分类的👇
经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇