不会这题,看了这篇博客后总结一下,这题主要有两种方法:
第一种是归位法:
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 }
和上面一种方法不同之处主要在标记的方法和判断标记的方法,而且它们是同时进行的。