由于数组中存的为1~n,都为正数,我们可以用正负号来表示下标为 i 的数在数组中是否出现。搜索遍历整个数组时,如果已经为负数,那么之前一定出现过一次,这个数就是我们要找的重复的数字。
最后哪些值为正数的下标i所对应的数字i+1就是在数组中没有出现过的数字。
切记:index=abs(nums[i])-1;取下标的时候一定要加绝对值!!原来的数可能已经添加了负号
代码(C语言)
int* findDuplicates(int* nums, int numsSize, int* returnSize){
int i,j,index;
int *rst=(int*)malloc(sizeof(int)*(numsSize+1));
*returnSize=0;
for(i=0;i<numsSize;i++){
index=abs(nums[i])-1;//记下数字num[i]在数组的下标
if(nums[index]<0){//小于0,那么数字index+1之前出现过
rst[(*returnSize)++]=index+1;
}
nums[index]=-abs(nums[index]);//否则,用负号来表示数字index+1出现过
}
return rst;
}
代码(C语言)
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize){
int i,index;
int *rst=(int*)malloc(sizeof(int)*(numsSize+1));
for(i=0;i<numsSize;i++){
index=abs(nums[i])-1;//下标
nums[index]=-abs(nums[index]);//将小标为index的数字改为负数,表示数字index+1出现过
}
*returnSize=0;
for(i=0;i<numsSize;i++){
if(nums[i]>0){//遍历过后,数字为负数,表示当前下标i所对应的数字i+1没有出现过
rst[(*returnSize)++]=i+1;
}
}
return rst;
}
这一题和上面不同的是数组长度不够用,由于缺失2个数字,因此额外增加两个空间的长度。做法和上述一致!
代码(C语言)
int* missingTwo(int* nums, int numsSize, int* returnSize){
int i,index;
//数组长度是少了两个空间的,我们额外添加一个数组来存放这两个数,下标分别为numsSize和numsSize+1,0表示没出现,-1表示出现
int* numsplus=(int*)malloc(sizeof(int)*2);
memset(numsplus,0,sizeof(numsplus));
for(i=0;i<numsSize;i++){
index=abs(nums[i])-1;
if(index<numsSize)
nums[index]=-abs(nums[index]);
else
numsplus[index-numsSize]=-1;
}
*returnSize=0;
for(i=0;i<2;i++){
if(numsplus[i]==0){
numsplus[(*returnSize)++]=numsSize+1+i;
}
}
for(i=0;i<numsSize;i++){
if(nums[i]>0){
numsplus[(*returnSize)++]=i+1;
}
}
return numsplus;
}
总结:
通过这种下标哈希法,我们用负号来表示当前下标的数字是否出现过,此法可以求任意重复或消失的数字。