题目
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
不算正解,但这很python
def findDisappearedNumbers(nums):
# 使用set
return list(set(range(1, len(nums) + 1)) - set(nums))
解法一:
- 将数组元素对应为索引的位置加n
- 遍历加n后的数组,若数组元素值小于等于n,则说明数组下标值不存在,即消失的数字
- 例如:4211->12 6 1 5,则消失的数字是3
cpp:
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
if(nums.empty()) return nums;
for(int i=0;i<nums.size();i++)
{
int index=(nums[i]-1)%nums.size();
nums[index]+=nums.size();
}
for(int i=0;i<nums.size();i++)
{
if(nums[i]<=nums.size())
res.push_back(i+1);
}
return res;
}
};
解法二
# 将所有正数作为数组下标,置对应数组值为负值。那么,仍为正数的位置即为(未出现过)消失的数字。
# 举个例子:
# 原始数组:[4,3,2,7,8,2,3,1]
# 重置后为:[-4,-3,-2,-7,8,2,-3,-1]
# 结论:[8,2] 分别对应的index为[5,6](消失的数字)
def findDisappearedNumbers(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
for num in nums:
index = abs(num) - 1
# 始终保持nums[index]为负数
nums[index] = -abs(nums[index])
return [i + 1 for i, num in enumerate(nums) if num > 0]
解法三
思路分析:
“抽屉原理”,即“一个萝卜一个坑”,但这道题比较让人头疼的是“不使用额外空间”。
以下介绍来自“百度百科”之“抽屉原理”词条:
抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有 n + 1 个元素放到 n 个集合中去,
其中必定有一个集合里至少有两个元素。” 抽屉原理有时也被称为鸽巢原理。它是组合数学中一个重要的原理。
这道题的一个子过程是“交换数组中两个位置的元素”,如果不使用额外的空间,可以使用“异或运算”代替。
方法:抽屉原理 + 基于“异或运算”交换两个变量的值
下面直接给结论:“基于异或运算”利用了“异或运算”是不进位的二进制加法。它有如下性质:
如果 a ^ b = c ,那么 a ^ c = b 与 b ^ c = a 同时成立,利用这一条,可以用于交换两个变量的值。
于是,交换两个变量的值,例如 a 和 b,不使用第三个变量,可以这样做:
a = a ^ b
b = a ^ b
a = a ^ b
我理解的方式就是自己在纸上写几个例子,也比较好记一些,因为右边都一样,左边依次是 a、b、a。
这里要特别注意一点,在数组中使用异或运算交换两个变量的值的时候,一定要保证这两个变量不相等,因为a ^ a = 0 。
这个方法实际效率并不高
def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
# 基于异或运算交换数组两个位置的元素,不使用额外的空间
def swap(nums, index1, index2):
# 这一步是必要的,否则会使得一个数变成 0
if index1 == index2:
return
nums[index1] = nums[index1] ^ nums[index2]
nums[index2] = nums[index1] ^ nums[index2]
nums[index1] = nums[index1] ^ nums[index2]
for i in range(len(nums)):
while nums[i] != nums[nums[i] - 1]:
# 如果不在位置上,并且它将要去的那个位置上的数不等于自己,则交换
swap(nums, i, nums[i] - 1)
return [i + 1 for i, num in enumerate(nums) if num != i + 1]