java找到所有数组中消失的数字_找到所有数组中消失的数字

题目描述

给定一个范围在  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]仔细看,数组中的每个元素,其实和数组下标是有一一对应关系的

b7b3f6d71369b5c81eaf8008984ede6e.png

这里的对应关系就是:

数组值1对应下标0

数组值2对应下标1

数组值3对应下标2

数组值4对应下标3

数组值5对应下标4

数组值6对应下标5

也就是数组下标+1正好等于 数组中的值

如果是一个乱序的数组会怎样呢?假设数组是[5,4,6,3,1,2],范围是[1,6],也没有缺失数字

70992f3ec277ecf07c7c5466097ac20c.png

这里仍然有一一对应关系:

数组值5对应下标4

数组值4对应下标3

数组值6对应下标5

数组值3对应下标2

数组值1对应下标0

数组值2对应下标1

没有缺失数字的情况下,不管是有序的、还是乱序的,都跟下标有一一对应关系。

现在我们来分析一个缺失数字的例子假设有数组[1,2,3,4,6,6]缺少数字5

cc0e214a7bf1c07e971d107f379ae545.png

我们用值和下标对应的这么一层关系,将数组重写一遍

第一个值是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]这个位置没动过重写了一遍数组之后,数组就变成了这个样子:

e478353623966af2e668ce09a18fd02b.png

由于下标4应该对应数字5,现在缺少了这个值,所以没人设置这个位置,于是第一遍处理完后,只有下标4这个位置的值是正数,其他位置的全部都是负数。这就好办了,我们遍历一遍数组,找到大于0的数,这个数是6,对应下标是4,所以缺失的数字是5

最后再看一个更复杂的例子数组[4,3,2,7,8,2,3,1],缺少5,6两个数字

626630e80229312d1e4a51d5021940bf.png

我们来看下第一趟的处理过程:

第一个数字是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

看完本文有收获?请转发分享给更多人

好文章,我在看❤️

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值