题意:给你一个整数数组,数组的值都是1≤a[i]≤n
(n
是数组的长度),有些数字会出现两次,但是有的数字只会出现一次。
找到所有在[1, n]
这个数组中,但是不在给的数组中的数。(也就是符合1≤a[i]≤n
,但是没有出现在给定数组中的数)
你能不用额外的存储空间并在O(n)时间内解决问题吗?你可以认为返回的结果数组并不占用额外的空间。
解析:这个题的意思非常好理解,但是如何在不占用额外的存储空间并且在O(n)时间内解决问题,是个需要思考的点,另外如果不注意的话,直接两层嵌套循环是会超时的。
先上一种比较有意思的解法:
这个解法有两个有趣的点,第一个是给数组前面加一个[0]
,这也是为第二点服务的;第二点是通过遍历数组中所有的值,并找到其对应的数组下标(题目设定,数的大小在数组长度内),将对应下标的值设置为负数,最后按照下标遍历,只要对应下标上的数值不为负数,说明这个下标的值不在数组中。
这里解释一下为什么要用绝对值abs()
函数,因为有些数字会出现两次,如果不使用绝对值abs()
做的话,会让出现了两次的数,转化为正数,结果就会出错了。
这个效率还ok,超过50%+。
def findDisappearedNumbers(self, nums):
nums = [0] + nums
for i in range(len(nums)):
index = abs(nums[i])
nums[index] = -abs(nums[index])
return [i for i in range(len(nums)) if nums[i] > 0]
再上一种最优解法,不仅效率高(超过95%的通过者),而且非常的简洁:
这种解法就是直接把数组转化为set
集合,并将数组的长度n
中包含的所有值转化为另一个set
,二者求差,并转化为list返回。
真的是非常非常吊的解法啊。
class Solution(object):
def findDisappearedNumbers(self, nums):
return list(set(range(1, len(nums) + 1)) - set(nums))
最后的最后,写到这里的时候突然有点突发奇想,如果我们在第一种解法中,直接nums
转化为set
在进行处理,那就不需要使用abs()
函数处理了,说不定一定程度上可以提高效率,这个留给读者去尝试吧。
为了避免读者踩坑,这里贴上超时的代码,请注意看清楚,这是没有通过的超时了的代码。
这段代码后半部分if x not in nums]
本质上还是使用循环判断是否存在的,也就是说这个代码是双重嵌套循环,这个解法死在了倒数第5组测试样例上,所以我个人估计题目的样例最后5组都是数量量比较大的(保守估计10万级(10的5次方)及以上)。
#超时代码
class Solution(object):
def findDisappearedNumbers(self, nums):
return [x for x in range(1, len(nums)+1) if x not in nums]
以上。