集合 S
包含从1到 n
的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。
给定一个数组 nums
代表了集合 S
发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入: nums = [1,2,2,4] 输出: [2,3]
注意:
- 给定数组的长度范围是 [2, 10000]。
- 给定的数组是无序的.
C语言版本,时间12ms
int* findErrorNums(int* nums, int numsSize, int* returnSize) {
int sum = 0, quotient=-1, remainder=0, miss, k;
int amount = (numsSize+7) >> 3;
char *set = (char *)malloc(a * sizeof(char));
set[0] = 1;
for (int i = 1; i < amount; i++) set[i] = 0;
for (int i = 0, n; i < numsSize; i++) {
sum += n = nums[i];
set[n>>3] |= (1 << (n&07));
}
for (int i = 0; i < amount; i++) {
if (~set[i]) {
quotient = i;
k = set[i];
break;
}
}
while (1 & k) {
k >>= 1;
remainder++;
}
miss = quotient << 3 + remainder;
int * ans = (int *)malloc(sizeof(int) * 2);
ans[1] = miss;
ans[0] = sum - (numsSize * (numsSize + 1) >> 1) + miss;
*returnSize = 2;
return ans;
}
程序思路:
利用char类型的位来存储出现的数字,遍历的过程中,同时计算数组和sum,最后找到miss掉的数字,并计算出重复数字
利用char类型数组来存储数字的原理:
char类型大小8位,每一个char字符都能存8个数字,在这里申请的是char数组set,则由总数numsSize可以得到需要的字符数,也即需要申请的char数组set的大小,这里我们记作amount = (numsSize + 7) >> 3 = (numsSize + 7) / 8;
遍历整个nums数组,对于出现的数字,则找到其在set中的位置,这个位置有两个量表示,这里记作quotient,remainder,分别代表该数字除以8得到的商和余数。则该数字存放在set[quotient]中,对应的是set[quotient]右数起第remainder+1位。
举个例子set[0] 共8位,则从右到左分别代表7,6,5,4,3,2,1,0,如下面所示
set[ 0 ] 7, 6, 5, 4, 3, 2, 1, 0
set[ 1 ] 15, 14, 13, 12, 11, 10, 9, 8
如果set[ 0 ] = 0 1 0 0 1 0 1 1,代表存在0, 1, 6
于是我们可得到数字n位于
quotient = n >> 3
remainder = n & 7 (n的最后3位)
则n位于set[quotient]这个数的remainder+1位
将该位和1<<remainder作取或操作就可以将该位置为 1
遍历结束后,检查缺的数在set数组的哪一个,然后再找到具体位置。
因为只缺了一个数,因此最后set数组上,每一位都是1,仅仅缺了数的有一位是 0
那么~set[i] 在set[i] 全为1时,值为0,当不全为1时,则不为0,那么通过判断 ~set[i]真假来判断位置
得到的miss = quotient << 3 + remainder
然后得到重复的数,输出结果