在给定数组中找到2个重复元素

时间:2015-08-30 10:37:02

标签: arrays algorithm search

给定一个带有n+2元素的数组,数组中的所有元素都在1n的范围内,并且所有元素只出现一次,除了两个出现两次的元素。

找到那两个重复的数字。例如,如果数组为[4, 2, 4, 5, 2, 3, 1],则n为5,有n+2 = 7个元素,除2和4外,所有元素只出现一次。

所以我的问题是如何使用XOR操作解决上述问题。我在其他网站上看到了解决方案,但我无法理解。请考虑以下示例:

arr[] = {2, 4, 7, 9, 2, 4}

  1. XOR每个元素。 xor = 2^4^7^9^2^4 = 141110
  2. 获取一个只有一个xor位的数字。由于我们可以轻松获得最右边的设置位,让我们使用它。
  3. set_bit_no = xor & ~(xor-1) = (1110) & ~(1101) = 0010。现在set_bit_no只会将xor设置为最右边的位。
  4. 现在将元素分成两组并在每组中做xor元素,我们得到非重复元素7和9.

1 个答案:

答案 0 :(得分:1)

是的,您可以使用XOR解决它。这个答案扩展到Paulo Almeida's great comment

该算法的工作原理如下:

因为我们知道数组包含范围[1 .. n]中的每个元素,所以我们首先对数组中的每个元素进行异或,然后将结果与范围[1 .. n]中的每个元素进行异或。由于XOR属性,唯一元素被抵消,结果是重复元素的异或(因为重复元素总共被异或3次,而所有其他元素被异或两次并被取消)。这存储在xor_dups

接下来,在xor_dups中找到一个1的位。再次,由于XOR的属性,在xor_dups中设置为1的位意味着该位在二进制文件中是不同的表示重复的数字。可以选择任何一个1作为下一步,我的实现选择最不重要的。这存储在diff_bit

现在,将数组元素拆分为两组:一组包含从xor_dups中选取的1位位置上具有0位的数字。另一组包含具有1位的数字。由于这个位在我们正在寻找的数字上有所不同,因此它们不能同时属于同一组。此外,每个号码的出现次数都归同一组。

所以现在我们差不多完成了。考虑具有0位的元素的组。将它们全部异或,然后将结果与范围[1..n]中在该位置上具有0位的所有元素进行异或,结果是该组的重复数字(因为仅有#s; s)在每组内重复一个数字,所有非重复数字都被取消,因为每一个都被异或两次,除了重复的数字被异常三次)。

冲洗,重复:对于具有1位的组,将它们全部异或,然后将结果与[1..n]范围内在该位置上具有1位的所有元素进行异或,并且结果是另一个重复的数字。

这是C:

中的一个实现
#include <assert.h>

void find_two_repeating(int arr[], size_t arr_len, int *a, int *b) {
    assert(arr_len > 3);
    size_t n = arr_len-2;
    int i;

    int xor_dups = 0;
    for (i = 0; i < arr_len; i++)
        xor_dups ^= arr[i];
    for (i = 1; i <= n; i++)
        xor_dups ^= i;

    int diff_bit = xor_dups & -xor_dups;
    *a = 0;
    *b = 0;

    for (i = 0; i < arr_len; i++)
        if (arr[i] & diff_bit)
            *a ^= arr[i];
        else
            *b ^= arr[i];

    for (i = 1; i <= n; i++)
        if (i & diff_bit)
            *a ^= i;
        else
            *b ^= i;
}

arr_len是数组arr的总长度(n+2的值),重复的条目存储在*a*b中(这些都是所谓的输出参数。)