使用重复值查找未排序数组中的缺失数字

时间:2015-04-13 19:53:55

标签: 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) ? 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;
}

5 个答案:

答案 0 :(得分:1)

由于有重复的元素,在编写我之前的解决方案之前我没想到,我相信解决方案的复杂性是最好的。

我建议,您可以只读取检查器数组,而不是xor'ing元素,以找到缺少的元素。

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;
}

这将减少取决于n的操作,使代码更快,更大的n。

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

鉴于您可能有重复项,我没有看到任何方法可以保留某些记录,显示您可以按每个值读取哪些值。基于一种或另一种单向散列函数(其中两种被提出然后被撤回)的方法不能自己完成这项工作。但是,通过将其与类似哈希的函数组合在一起,可以节省扫描所见值的记录的工作量。例如,

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;
}

这无疑与您的版本非常相似,但我更有信心它会起作用,而且我认为它的运行速度可能会稍快。

请注意,我没有声明任何变量register - 编译器比我选择哪些变量应该存在于寄存器中要好得多,哪些不是,并且没有义务就此问题采纳我的建议无论如何。

此外,checker数组的元素具有类型char,允许一次存放在CPU缓存行中的数量是它们类型int的四倍(假设为1) -byte char和4字节int s。。

另请注意,我避免计算不同的值或以其他方式在循环内分支(三元表达式可以在没有分支的情况下实现)。避免计数和条件语句将加速确实缺少一个值的情况,并且实际上可能会或可能不会减慢没有丢失的情况。增益可能来自于不仅仅是拥有更少的代码 - 有时这种简化也可以让编译器生成更有效的指令序列。

当然,如果可能缺少一个以上的值,那么整个事情就是垃圾(问题没有明确说明)。

答案 3 :(得分:1)

原始程序已经很快了。但是,鉴于问题陈述,可以通过更改它来加快速度:

        if(++counter == 100)
            return -1;

到此:

        if(++counter == 99)
            return xor;

此更改会导致程序在找到99个不同的元素时立即返回答案。因此,如果数组非常大,则只处理数组的一小部分,并且可以忽略数组的其余部分。这取决于问题陈述,该陈述声明已知缺少一个元素。

答案 4 :(得分:1)

Javia1492在他的回答中有一个主要想法:总结数字。

checker数组会阻止您将两次相同的数字相加。

counter变量计算结束搜索的不同数字的数量,然后在您已经有99个不同的值时测试数组中的整个n数字。

它也可以像你一样使用xor运算符,但我不太喜欢它,因为1 ^ 2 ^ 3 ^ .. ^ 99 == 0是某种特殊情况你可以&#39; t用1 ^ 2 ^ .. ^ N。

进行推广
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
}