leetcode 645 错误的集合 (Set Mismatch)

集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。

给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

示例 1:

输入: nums = [1,2,2,4]
输出: [2,3]

注意:

  1. 给定数组的长度范围是 [2, 10000]。
  2. 给定的数组是无序的.

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

然后得到重复的数,输出结果

猜你喜欢

转载自blog.csdn.net/qq_35215641/article/details/81783498
今日推荐