题目描述
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。找到所有在 [1, n] 范围之间没有出现在数组中的数字。您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
输入:[4,3,2,7,8,2,3,1]输出:[5,6]
题解
注意题目要求不能使用额外空间,这就是题目的难点所在。这道题的描述部分包含了一个非常重要的信息,1 ≤ a[i] ≤ n,即每个数字本身都对应一个i-1的数组下标。我们可以利用数组内容本身跟数字下标的关联找出缺失的数字。
扫描两遍数组:
第一遍,将所有数字做标记
第二遍,根据标记信息找出缺失的数字。
下面来看详细分析假设有数组[1,2,3,4,5,6]这个数组是有序的,而且也没有缺失数字,范围是[1,6]仔细看,数组中的每个元素,其实和数组下标是有一一对应关系的
这里的对应关系就是:
数组值1对应下标0
数组值2对应下标1
数组值3对应下标2
数组值4对应下标3
数组值5对应下标4
数组值6对应下标5
也就是数组下标+1正好等于 数组中的值
如果是一个乱序的数组会怎样呢?假设数组是[5,4,6,3,1,2],范围是[1,6],也没有缺失数字
这里仍然有一一对应关系:
数组值5对应下标4
数组值4对应下标3
数组值6对应下标5
数组值3对应下标2
数组值1对应下标0
数组值2对应下标1
没有缺失数字的情况下,不管是有序的、还是乱序的,都跟下标有一一对应关系。
现在我们来分析一个缺失数字的例子假设有数组[1,2,3,4,6,6]缺少数字5
我们用值和下标对应的这么一层关系,将数组重写一遍
第一个值是1,对应下标是0,将arr[0]设置为-arr[0],即-1
第二个值是2,对应下标是1,将arr[1]设置为-arr[1],即-2
第三个值是3,对应下标是2,将arr[2]设置为-arr[2],即-3
第四个值是4,对应下标是3,将arr[3]设置为-arr[3],即-4
第五个值是6,对应下标是5,
将arr[5]设置为-arr[5],即-6
第六个值是6,对应下标是5,
将arr[5]设置为-arr[5],即-6
第五个、第六个值相同,他们修改的是同一个下标,都将arr[5]改了一次但是arr[4]这个位置没动过重写了一遍数组之后,数组就变成了这个样子:
由于下标4应该对应数字5,现在缺少了这个值,所以没人设置这个位置,于是第一遍处理完后,只有下标4这个位置的值是正数,其他位置的全部都是负数。这就好办了,我们遍历一遍数组,找到大于0的数,这个数是6,对应下标是4,所以缺失的数字是5
最后再看一个更复杂的例子数组[4,3,2,7,8,2,3,1],缺少5,6两个数字
我们来看下第一趟的处理过程:
第一个数字是4,对应下标3,将arr[3]设置为-7
第二个数字是3,对应下标2,将arr[2]设置为-2
第三个数字是2,对应下标1,将arr[1]设置为-3
第四个数字是7,对应下标6,将arr[6]设置为-3
第五个数字是8,对应下标7,将arr[7]设置为-1
第六个数字是2,对应下标1,将arr[1]设置为-3
第七个数字是3,对应下标2,将arr[2]设置为-2
第八个数字是1,对应下标0,将arr[0]设置为-4
第一趟处理完了之后,我们开始第二趟扫描,也就是上图中第二个数组这个数组中8,2两个元素是大于0的8对应下标4,所以4+1,即缺少5这个数字2对应下标5,所以5+1,即缺少6这个数字
时间复杂度:O(N)空间复杂度:O(1)
java代码:
class Solution{ public List findDisappearedNumbers(int[] nums){ List res = new ArrayList(); //第一遍扫描,根据数组的值找到对应的下标,比如3对应下标2 //将arr[2]设置成负数 for(int i=0;i0) { nums[index] *= -1; } } //第二遍扫描,找到所有非负数,非负数所在的下标+1,即为缺失的数字 for(int i=1;i<=nums.length;++i) { if(nums[i-1]>0) { res.add(i); } } return res; }}
python代码:
class Solution(object): def findDisappearedNumbers(self, nums): """ :type nums: List[int] :rtype: List[int] """ res = [] # 第一遍扫描,根据数组的值找到对应的下标,比如3对应下标2 # 将arr[2]设置成负数 for i in nums: index = abs(i)-1 if nums[index]>0: nums[index] *= -1 # 第二遍扫描,找到所有非负数,非负数所在的下标+1,即为缺失的数字 for i in xrange(len(nums)): if nums[i]>0: res.append(i+1) return res
看完本文有收获?请转发分享给更多人
好文章,我在看❤️