问题来源: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. HTML的各种基本标签

      一 .head中的各种标签                1.       <!DOCTYPE html><html>文档类型声明   声明当前文件是一个HTML5文件文档 ...

  2. Python处理Excel生成CSV文档

    Python是一种解释型的.动态数据类型的.面向对象的高级程序设计语言.拥有丰富的处理数据和文本类库,并且得益于它是一种解释型的语言,在程序修改和功能扩展上,可以很容易做到大规模的调整.综合考虑Pyt ...

  3. [LeetCode] IPO 上市

    Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Cap ...

  4. [LeetCode] K-diff Pairs in an Array 数组中差为K的数对

    Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in t ...

  5. org.apache.commons.lang3.tuple.Pair 作为更新参数,XML 中的 Sql 取不到值、报错

    项目用的 Mybatis,今天改一个需求,落地实现是批量更新,且只需要根据主键(id)来更新一个字段(name). 于是,没有犹豫,像下面这样设计了数据结构: 既然是批量更新,那外层肯定是 List ...

  6. 医疗器械c#上位机开发指引教程

    此教程面向的读者:对医疗器械上位机编程有兴趣,或者急需了解医疗器械(尿常规.血液分析.生化.心电.B超等医疗下位仪器)的编程流程.编程细节的程序员. 1.得到仪器协议 当我们需要与医疗器械等下位机数据 ...

  7. MySQL的安全机制

    MySQL的安全机制: 1.MySQL登录 mysql -u账户 -p密码 -h127.0.0.1 -P端口 数据库名 mysql -h hostname|hostIP -p port -u user ...

  8. [SCOI 2010]字符串

    Description lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数.现在lxhgw ...

  9. 计蒜客NOIP模拟赛(2) D2T2紫色百合

    [问题描述] “牵着你的手的是她,路边开满了紫色的百合花……” 你从梦中醒来,却依然忘不了梦中的她百合花,每朵百合花都有一个权值,在二进制下写成一行‘1’,第i朵紫色百合的权值在二进制下写成i个‘1’ ...

  10. 2015 多校联赛 ——HDU5302(构造)

    Connect the Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...