问题来源: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. 批量导入数据到hive表中:假设我有60张主子表如何批量创建导入数据

    背景:根据业务需要需要把60张主子表批量入库到hive表. 创建测试数据: def createBatchTestFile(): Unit = { to ) { val sWriter = new P ...

  2. Oracle表空间的管理方式

    解释说明:表空间是一个逻辑概念:=> oracle 逻辑概念段区块管理方式: number one => tablespace number two=> segments Oracl ...

  3. 基于vue2.0的一个系统

    前言 这是一个用vue做的单页面管理系统,这里只是介绍架子搭建思路 前端架构 沿用Vue全家桶系列开发,主要技术栈:vue2.x+vue-router+vuex+element-ui1.x+axios ...

  4. 自己使用Vue全家桶问题合集(很多eslint规范问题)

    遇到很多问题一一道来. 1.vue报错 Do not use built-in or reserved HTML elements as component id:header 组件,不能和html标 ...

  5. leetcode 561.Array Partition I-easy

    Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1 ...

  6. [LeetCode] Minimum Time Difference 最短时间差

    Given a list of 24-hour clock time points in "Hour:Minutes" format, find the minimum minut ...

  7. [Codeforces 176B]Word Cut

    Description 题库链接 给你两个字符串 \(S\) 和 \(T\) ,准许你 \(k\) 次操作,每次将字符串左右分成两个非空的部分,再交换位置,问你有多少种不同的操作方法将 \(S\) 串 ...

  8. [NOI2011]道路修建

    题目描述 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 条双向道路. 每条道 ...

  9. [HNOI2008]明明的烦恼

    Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为 ...

  10. HDU 5412 CRB and Queries 动态整体二分

    Problem Description There are N boys in CodeLand.Boy i has his coding skill Ai.CRB wants to know who ...