442.Find All Duplicates in an Array

参考博客

不会这题,看了这篇博客后总结一下,这题主要有两种方法:

第一种是归位法:

 1 void swap(int *a,int *b)
 2 {
 3     int temp=*a;
 4     *a=*b;
 5     *b=temp;
 6 }
 7 
 8 int* findDuplicates(int* nums, int numsSize, int* returnSize)
 9 {
10     int *result=malloc(numsSize*(sizeof(int)));
11     *returnSize=0;
12     
13     for(int i=0;i<numsSize;i++)
14     {
15         while(nums[i]!=i+1 && nums[nums[i]-1]!=nums[i])
16         swap(&nums[i],&nums[nums[i]-1]);
17     }
18     
19     for(int i=0;i<numsSize;i++)
20     {
21         if(nums[i]!=i+1)
22         result[(*returnSize)++]=nums[i];
23     }
24     
25     return result;
26 }

但是对于其中的均摊分析,还是不很理解。

 

第二种归纳为“标记法”(在不需要额外空间的情况下来标记)

大概分为三个步骤

 

1.因为什么原因来标记一个位置

 

2.用什么标记方法

 

3.用什么方法判断这个标记

 

所以对于上面提到的那篇博客的,剩余的两种方法都可以归纳为标记法

 

 1 int* findDuplicates(int* nums, int numsSize, int* returnSize)
 2 {
 3     int *result=malloc(numsSize*(sizeof(int)));
 4     *returnSize=0;
 5     
 6     for(int i=0;i<numsSize;i++)
 7         nums[nums[i]%(numsSize+3)-1]+=numsSize+3;
 8     
 9     for(int i=0;i<numsSize;i++)
10     {
11         if(nums[i]/(numsSize+3)>1)
12         result[(*returnSize)++]=i+1;
13     }
14 
15     return result;
16 }

上面是博客中提到的取余法

分解来看:

 

1.因为各元素出现次数不同来标记一个位置

 

2.标记的方法是对一个位置上 的 元素 对应 的 位置 加上一个数,为了第三步的方便,可以加上numsSize+1或比它大的数

 

3.检验这个标记的方法:对每个位置的新元素都除以第二步加的那个数,因为第二步已经规定加的那个数大于等于numsSize+1,所以当商等于零时,

就是该位置本该出现的元素并没有出现,同理商为一则是出现了一次。。。。。。

 

另一个标记的方法是取负

 

 1 int* findDuplicates(int* nums, int numsSize, int* returnSize)
 2 {
 3     int *result=malloc(numsSize*(sizeof(int)));
 4     *returnSize=0;
 5     
 6     for(int i=0;i<numsSize;i++)
 7     {
 8         int index=abs(nums[i])-1;
 9         
10         if(nums[index]>0)
11         nums[index]=-nums[index];
12         else
13         result[(*returnSize)++]=index+1;
14     }
15     
16     return result;
17 }

 

和上面一种方法不同之处主要在标记的方法和判断标记的方法,而且它们是同时进行的。

posted @ 2017-03-01 11:59  lan126  阅读(144)  评论(0编辑  收藏  举报