C 在具有重复值的未排序数组中查找缺少的数字

C 在具有重复值的未排序数组中查找缺少的数字,c,performance,numbers,find,xor,C,Performance,Numbers,Find,Xor,我有一个大小为“n”的数组,其中包含[0-99]之间的未排序和重排序整数。我已经知道少了一个号码。那么,找到丢失号码的最快方法是什么? 这是我到目前为止在C中的解决方案 int find_missing_number(int array[], int n) { char checker[100] = {0}; int xor = 0, counter = 0, i, temp; //xor = (n%4==0) ? 0 : (n%4==1) ? n-1 : (n%4==2

我有一个大小为“n”的数组,其中包含[0-99]之间的未排序和重排序整数。我已经知道少了一个号码。那么,找到丢失号码的最快方法是什么? 这是我到目前为止在C中的解决方案

int find_missing_number(int array[], int n)
{
    char checker[100] = {0};
    int xor = 0, counter = 0, i, temp;
    //xor = (n%4==0) ? 0 : (n%4==1) ? n-1 : (n%4==2) ? 1 : n;

    for(i = 0; i < n; i++)
        if(checker[temp = array[i]] == 0)
        {
            checker[temp] = 1;
            xor ^= temp;
            if(++counter == 99)
                return xor;
        }

    return -1;
}
int-find_缺失_编号(int-array[],int-n)
{
字符检查器[100]={0};
int xor=0,计数器=0,i,温度;
//xor=(n%4==0)?0:(n%4==1)?n-1:(n%4==2)?1:n;
对于(i=0;i
由于存在重复的元素,在编写上一个解决方案之前,我没有看到这些元素,所以我认为您的解决方案的复杂性是最好的

我建议,不必对元素进行异或运算,只需读取棋盘格数组即可找到缺少的元素

int find_missing_number(int array[], int n)    
{
    int checker[100] = {0};

    for(int i = 0; i < n; i++)
        checker[array[i]]++;

    for(int i=0; i <100; i++)
        if(0 == checker[i])
            return i;
}
int-find_缺失_编号(int-array[],int-n)
{
int checker[100]={0};
对于(int i=0;i对于(int i=0;i,由于存在重复的元素,在编写上一个解决方案之前,我没有看到这些元素,所以我相信您的解决方案的复杂性是最好的

我建议,不必对元素进行异或运算,只需读取棋盘格数组即可找到缺少的元素

int find_missing_number(int array[], int n)    
{
    int checker[100] = {0};

    for(int i = 0; i < n; i++)
        checker[array[i]]++;

    for(int i=0; i <100; i++)
        if(0 == checker[i])
            return i;
}
int-find_缺失_编号(int-array[],int-n)
{
int checker[100]={0};
对于(int i=0;i
我不完全确定这是不是一个更快的方法,但你可以选择尝试

编辑:如果没有重复的值,这将起作用。

您可以在O(n)中执行此操作。迭代数组并计算所有数字的总和。现在,从1到n的自然数总和可以表示为Nx(n+1)/2。在您的情况下,n=99。从Nx(n+1)/2中减去数组的总和,其中n=99。 这是丢失的数字。在计算和的迭代过程中可以检测到空槽

我不完全确定这是不是一个更快的方法,但你可以选择尝试


编辑:如果您没有重复的值,这将起作用。

鉴于您可能有重复的值,我看不出任何方法可以保存某种类型的记录,其中的值已被看到,您可以在每个值的基础上读取。方法基于一种或另一种单向散列函数(其中两个被提议,然后又被撤回)无法单独完成这项工作。但是,可能您可以通过将其与散列函数相结合,在填充后省去扫描已看到值记录的工作量。例如

int find_missing_number(int array[], int n)
{
    char checker[100] = {0};
    int xor = XOR_OF_1_TO_100;
    int i;

    for(i = 0; i < n; i++) {
        xor ^= (checker[array[i]] ? 0 : array[i] + 1);
        checker[array[i]] = 1;
    }

    return xor - 1;
}
int-find_缺失_编号(int-array[],int-n)
{
字符检查器[100]={0};
int xor=从1到100的xor;
int i;
对于(i=0;i
无可否认,这与您的版本非常相似,但我更相信它会起作用,而且我认为它可能运行得稍快一些

请注意,我没有声明任何变量
寄存器
——编译器比我更擅长选择哪些变量应该存在于寄存器中,哪些不存在于寄存器中,而且它在任何情况下都没有义务接受我的建议

此外,
checker
数组的元素具有类型
char
,允许一次驻留在CPU缓存线中的数量是类型
int
的四倍(假设为1字节
char
s和4字节
int
s)

还要注意的是,我避免计算不同的值或循环内部的分支(三元表达式可以在没有分支的情况下实现)。避免使用计数和条件语句将加快确实缺少一个值的情况,并且在实践中可能会或可能不会减慢缺少任何值的情况。这种好处可能不仅仅是因为代码更少——有时这样的简化可以让编译器生成更高效的指令序列,例如o


当然,整件事都是垃圾(而且问题没有明确说明)如果缺少一个以上的值。

考虑到您可能有重复的值,我看不出任何方法可以保存某种类型的记录,您可以在每个值的基础上读取这些值。基于一种或另一种单向散列函数的方法(其中两种被提出,然后被撤回)无法单独完成此项工作。但是,可能您可以在填充已看到值的记录后,通过将其与散列函数相结合,省去扫描该记录的工作量。例如

int find_missing_number(int array[], int n)
{
    char checker[100] = {0};
    int xor = XOR_OF_1_TO_100;
    int i;

    for(i = 0; i < n; i++) {
        xor ^= (checker[array[i]] ? 0 : array[i] + 1);
        checker[array[i]] = 1;
    }

    return xor - 1;
}
int-find_缺失_编号(int-array[],int-n)
{
字符检查器[100]={0};
int xor=从1到100的xor;
int i;
对于(i=0;i
无可否认,这与您的版本非常相似,但我更相信它会起作用,而且我认为它可能运行得稍快一些

请注意,我没有声明任何变量
寄存器
——编译器比我更擅长选择哪些变量应该存在于寄存器中,哪些不存在于寄存器中,而且它在任何情况下都没有义务接受我的建议

另外,
checker
数组的元素具有类型
char
,一次驻留在CPU缓存线中的数量是类型
int
的四倍(假设为1-byt)
int find_missing_number(int array[], int n)
{
    char checker[100];
    register int sum = 0, counter = 0, i, temp;

    memset(checker, 0, sizeof(checker));
    for (i = 0; i < n; i++)
    {
        if (checker[temp = array[i]] == 0)
        {
            checker[temp] = 1;
            sum += temp;
            if (++counter == 99)
               break;
        }
    }
    return 4950 - sum; // (100*99)/2 - sum
}