一尘不染

在数组中查找一个元素,其中每个元素重复奇数次(但不止一次出现),并且仅出现一次

algorithm

您有一个数组,其中每个数字都重复奇数次(但不止一次出现)。恰好一个数字出现一次。您如何找到仅出现一次的号码?

e.g.: {1, 6, 3, 1, 1, 6, 6, 9, 3, 3, 3, 3}

答案是9。

我正在考虑拥有一个哈希表,然后仅对计数为1的元素进行计数。这似乎是微不足道的,并且我没有利用其他元素重复奇次的事实。有没有更好的方法。


阅读 245

收藏
2020-07-28

共1个答案

一尘不染

我相信您仍然可以使用XOR的基本思想来巧妙地解决此问题。

首先,让我们更改问题,以使一个数字出现一次,而所有其他数字出现三次。


算法:

A是length的数组n

   int ones = 0;  
   int twos = 0;  
   int not_threes, x;

   for (int i=0; i<n; ++i) {  
            x =  A[i];  
            twos |= ones & x;  
            ones ^= x;  
            not_threes = ~(ones & twos);  
            ones &= not_threes;  
            twos &= not_threes;  
   }

恰好发生一次的元素存储在中ones。这会占用O(n)时间和O(1)空间。

我相信我可以将这个想法扩展到问题的一般情况,但是也许你们中的一个可以更快地做到这一点,所以我现在将其保留,并在何时以及是否可以推广该解决方案时对其进行编辑。


说明:

如果问题是这样的:“一个元素出现一次,所有其他元素出现偶数次”,那么解决方案将是对元素进行XOR。原因是x^x = 0,因此所有成对的元素都将消失,仅留下孤独的元素。如果我们在这里尝试相同的策略,那么我们将得到不同元素的XOR,这不是我们想要的。

而是,上述算法执行以下操作:

  • ones 是到目前为止已经出现一次的所有元素的XOR
  • twos 是到目前为止已出现两次的所有元素的XOR

每次当我们x成为数组中的下一个元素时,都会出现以下三种情况:

  1. 如果这是第一次x出现,则将其异或为ones
  2. 如果这是第二次x出现,则将其取出ones(再次对其进行XOR处理)并XOR到twos
  3. 如果这是第三次x出现,则将其从ones和中取出twos

因此,最后ones将是仅一个元素的XOR,即不再重复的孤独元素。我们需要查看5行代码以了解其工作原理:后五行x = A[i]

如果这是第一次x出现,那么ones&x=ones这样twos保持不变。行ones ^= x;异或xones权利。因此x在恰好一个onestwos,所以没有在最后三行要么发生onestwos

如果这是第二次x出现,则ones已经有x(通过上面的说明),所以现在twos用line来获取它twos |= ones & x;。此外,由于ones具有x,因此该行从中ones ^= x;删除(因为)。再次,最后三行自做的正好一个没有和现在有。x``ones``x^x=0``ones``twos``x

如果这是第三次x出现,则ones没有x,但twos确实。因此,第一行让我们twos继续x,第二行添加xones。现在,由于两者都具有ones并且twos具有x,因此最后三行x将从两者中删除。


概括:

如果一些数字出现5次,则此算法仍然有效。这是因为第4次未x出现,也不onestwos。前两行,然后添加xones,而不是twos最后三行什么也不做。第5次x出现,ones但不在twos。第一行将其添加到中twos,第二行将其从中删除ones,最后三行不执行任何操作。

问题是第6次x出现,它是从ones和提取的twos,因此它ones在第7次传回时又添加回去。我正在尝试一种聪明的方法来防止这种情况,但是到目前为止,我还是空虚的。

2020-07-28