问题来源:Find All Numbers Disappeared in an Array

很久没有刷题了,感觉大脑开始迟钝,所以决定重拾刷题的乐趣。一开始不要太难,选一些通过率高的题目做,然后就看到了这个题目。我有些吃惊,这个题我虽然知道两种解法,但本身还是有难度的,居然通过率这么高。然后就搜索相关网页,看到一个和它很接近的题目《Find All Duplicates in an Array》,然后就释然了。这两个题目有相同的题干,只是问题略微不同,解法有相似之处。估计是因为题号太接近了,会做第一个之后,第二个也很容易就做对了。本文主要解析《Find All Numbers Disappeared in an Array》,顺便简单解释一下《Find All Duplicates in an Array》。

该题的含义是:给定一个长度为n的数组,数组元素是1~n。但是有些元素出现一次,有些元素出现两次,从而也会导致有些元素不出现。现在让我们找到哪些元素没有出现。另外一个题目是让我们找到出现两次的元素。时间复杂度O(n),空间复杂度O(1)。

解法一

第一种方法是利用之前博客《数组统计分析的另一种方法》介绍的方法—元素归位法。元素归位法很容易理解,就是将n个元素交换到它应该在的位置。例如,元素5就放到位置4(下标从0开始)。这里需要注意一点,将某个元素交换到正确位置可能会导致当前位置的元素还不在正确位置,需要继续交换直到不能交换为止,伪代码如下:

for i=1:n
while canSwap(i) do swap(i);

将元素归位之后,我们就很容易获得哪些元素没有出现。当某个位置不是正确元素的时候,就意味着这个元素没有出现。也即针对没有出现的元素,我们只需要返回下标;针对出现两次的元素,我们只需要返回该位置的值。

这里有一个疑问,伪代码有两个for循环,复杂度是不是O(n2)呢?不是,复杂度还是O(n),这个可以通过均摊分析来解释:如果满足交换条件,则每次都会使一个元素处在正确位置,因为总共有n个元素,所以至多需要n-1次交换(交换完n-1个元素,第n个元素自动满足)即可使所有的元素处在正确位置,也即while循环至多执行O(n)次,每次的平摊代价是O(1)。所以上述交换操作的复杂度为O(n)。

C语言版代码如下:

void swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
} int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {
int* result=(int*)malloc(sizeof(int)*numsSize); for(int i=0;i<numsSize;i++)
{
while(nums[i]!=i+1&&nums[nums[i]-1]!=nums[i])
{
swap(&nums[i],&nums[nums[i]-1]);
}
} *returnSize=0; for(int i=0;i<numsSize;i++)
{
if(nums[i]!=i+1)
{
result[*returnSize]=i+1;
*returnSize=*returnSize+1;
}
} return result;
}

解法二

在待字闺中公众号《数组统计分析》中,陈利人老师曾经给出另外一种解法—取余法,道理也比较好理解。数组的元素范围为1~n,第一次循环首先把每个元素对应的位置加上(n+1);第二次循环把每个位置除以(n+1),如果该位置为0,表示某个元素没有出现;如果该位置等于2,表示出现两次。

原理是什么呢?在第一次循环中,我们其实是将每个位置变成k*(n+1)+i,其中k表示该位置加(n+1)的次数,取值为0、1、2,i表示该位置本来的元素。在第二次循环中,因为i的范围是1~n,所以除以(n+1)就等于0,从而我们就获得了k的值。根据k的值,我们就很容易知道哪些元素没有出现,哪些元素出现了多次。

C语言版代码如下:

int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {
int* result=(int*)malloc(sizeof(int)*numsSize); *returnSize=0; for(int i=0;i<numsSize;i++)
{
nums[nums[i]%(numsSize+1)-1]+=(numsSize+1);
} for(int i=0;i<numsSize;i++)
{
if(nums[i]/(numsSize+1)==0)
{
result[*returnSize]=i+1;
*returnSize=*returnSize+1;
}
} return result;
}

解法三

在Top Solution中,有网友分享了一种很奇妙的解法—取负法。含义是:将元素对应的位置取负。简单一句话可能不好理解,我们举个例子。假设在位置k放了元素i,则在取负的过程中i的取值有两种可能:为正,表示当前尚未遇到元素k将该位置取负;为负,表示当前已经有元素k出现,并将元素取负。但是我们不关心k,我们关心元素i。元素i既然出现,我们就看一下位置i:为正,表示这是元素i第一次出现,我们将位置i取负;为负,表示元素i已经出现过一次,我们不做任何操作。不管一个元素出现一次还是两次,只要出现它对应的位置就会被取负。当某个元素不出现的时候,该元素对应的位置始终访问不到,所以还是正值,通过这种方法我们就可以找到哪些元素没有出现。

通过上面的分析我们也很容易知道,在取负的过程中,如果发现要取负的位置已经为负,说明这个元素已经出现过,也即该元素出现了两次,我们可以将该元素保留下来。

C语言版代码如下:

int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {
int* result=(int*)malloc(sizeof(int)*numsSize); for(int i=0;i<numsSize;i++)
{
int index=abs(nums[i])-1; if(nums[index]>0) nums[index]=-nums[index];
} *returnSize=0; for(int i=0;i<numsSize;i++)
{
if(nums[i]>0)
{
result[*returnSize]=i+1;
*returnSize=*returnSize+1;
}
} return result;
}

针对《Find All Duplicates in an Array》,采用取负法实现的C语言代码如下:

int* findDuplicates(int* nums, int numsSize, int* returnSize) {
int* result=(int*)malloc(sizeof(int)*numsSize); *returnSize=0; for(int i=0;i<numsSize;i++)
{
int index=abs(nums[i])-1; if(nums[index]>0)
{
nums[index]=-nums[index];
}
else
{
result[*returnSize]=index+1;
*returnSize=*returnSize+1;
}
} return result;
}

leetcode之Find All Numbers Disappeared in an Array的更多相关文章

  1. LeetCode 448. Find All Numbers Disappeared in an Array (在数组中找到没有出现的数字)

    Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and ot ...

  2. leetcode 448. Find All Numbers Disappeared in an Array -easy (重要)

    题目链接: https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/ 题目描述: Give ...

  3. LeetCode "448. Find All Numbers Disappeared in an Array"

    My first reaction is to have an unlimited length of bit-array, to mark existence. But if no extra me ...

  4. 5. Leetcode 448. Find All Numbers Disappeared in an Array

    Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and ot ...

  5. LeetCode 448 Find All Numbers Disappeared in an Array 解题报告

    题目要求 Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice a ...

  6. LeetCode: 448 Find All Numbers Disappeared in an Array(easy)

    题目: Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice an ...

  7. LeetCode 448. Find All Numbers Disappeared in an Array找到所有数组中消失的元素

    题目 给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次. 找到所有在 [1, n] 范围之间没有出现在数组中的数字. 您能 ...

  8. [LeetCode] 448. Find All Numbers Disappeared in an Array 找到数组中消失的数字

    题目描述 给定n个数字的数组,里面的值都是1-n,但是有的出现了两遍,因此有的没有出现,求没有出现值这个数组中的值有哪些. 要求不能用额外的空间(除了返回列表之外),时间复杂度n 思路 因为不能用额外 ...

  9. LeetCode——Find All Numbers Disappeared in an Array

    LeetCode--Find All Numbers Disappeared in an Array Question Given an array of integers where 1 ≤ a[i ...

随机推荐

  1. java 反射(Reflection)

    看了很多关于java 反射的文章,自己把所看到的总结一下.对自己,对他人或多或少有帮助吧. Java Reflection是什么? 首先来看看官方文档Oracle里面对Reflection的描述: R ...

  2. 0323-DOM基础操作

    dom操作 1.找到元素(标签对象) 标签名: document.getElementsByTagName()[]; //返回的是数组类型,需要有下标来找内容 属性: document.getElem ...

  3. 使用Docker安装Jenkins

    Jenkins Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 环境准备 腾讯云 硬件配置: ...

  4. [LeetCode] Largest Number At Least Twice of Others 至少是其他数字两倍的最大数

    In a given integer array nums, there is always exactly one largest element. Find whether the largest ...

  5. animation-timing-function的steps详解

    W3C里的定义: animation-timing-function 规定动画的速度曲线. 这个属性有很多取值, linear: 线性过渡.等同于贝塞尔曲线(0.0, 0.0, 1.0, 1.0) e ...

  6. [HDU 2036]改革春风吹满地

    Description “ 改革春风吹满地,不会AC没关系;实在不行回老家,还有一亩三分地.谢谢!(乐队奏乐)”话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而且,还竟然 ...

  7. [Codeforces 606C]Sorting Railway Cars

    Description An infinitely long railway has a train consisting of n cars, numbered from 1 to n (the n ...

  8. Codefroces 850C Arpa and a game with Mojtaba

    Description两个人Van♂游戏.给出$n$个正整数$ai$两人轮流操作,每次选出一个素数$p$和一个幂数$k$,选择的前提为该$n$个数中有$p^{k}$的倍数.接着将所有的$p^{k}$的 ...

  9. HDU3389 Game

    Problem Description Bob and Alice are playing a new game. There are n boxes which have been numbered ...

  10. hdu 5885 FFT

    XM Reserves Time Limit: 10000/10000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)T ...